{'vendor-dir'} ) ) { array_unshift( $vendor_paths, EE_CLI_ROOT . '/../../../' . $composer->{'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 = EE_CLI_ROOT . "/php/commands/$name.php"; if ( is_readable( $path ) ) { include_once $path; } } function load_all_commands() { $cmd_dir = EE_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; } /** * Output items in a table, JSON, CSV, ids, or the total count * * @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 ) { $assoc_args = compact( 'format', 'fields' ); $formatter = new \EE_CLI\Formatter( $assoc_args ); $formatter->display_items( $items ); } /** * Write data as CSV to a given file. * * @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 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 */ function launch_editor_for_input( $input, $title = 'ee-cli' ) { $tmpfile = wp_tempnam( $title ); if ( !$tmpfile ) \EE_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 ) { if ( ! file_exists( $template_name ) ) $template_name = EE_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 ); } function make_progress_bar( $message, $count ) { if ( \cli\Shell::isPiped() ) return new \EE_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 * * @param string $method * @param string $url * @param array $headers * @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( EE_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'] ) ){ EE_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 \EE_CLI::warning( $ex->getMessage() ); $options['verify'] = false; try { return \Requests::request( $url, $headers, $data, $method, $options ); } catch( \Requests_Exception $ex ) { \EE_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 * * @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. * * @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 get_flag_value( $args, $flag, $default = null ) { return isset( $args[ $flag ] ) ? $args[ $flag ] : $default; } /** * Return OS Information * @return array */ function get_OS(){ if (strtolower(substr(PHP_OS, 0, 5)) === 'linux') { $vars = array(); $files = glob('/etc/*-release'); foreach ($files as $file) { $lines = array_filter(array_map(function($line) { // split value from key $parts = explode('=', $line); // makes sure that "useless" lines are ignored (together with array_filter) if (count($parts) !== 2) return false; // remove quotes, if the value is quoted $parts[1] = str_replace(array('"', "'"), '', $parts[1]); return $parts; }, file($file))); foreach ($lines as $line) $vars[$line[0]] = $line[1]; } } return $vars ; }