/** * 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' => '*****@*****.**'); $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; }
$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) { $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");
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), null, self::get_process_env_variables())->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'); }
/** * 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. * * ## 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, '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); 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); $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."); }
/** * 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 * @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) { $proc = Process::create($command); $results = $proc->run(); if ($results->return_code && $exit_on_error) { exit($results->return_code); } if ($return_detailed) { return $results; } else { return $results->return_code; } }
/** * 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.'); }
{ $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); });
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); }
/** * 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; } }