Skip to content

Commit

Permalink
Merge branch 'master' into code-standards-4
Browse files Browse the repository at this point in the history
  • Loading branch information
danielbachhuber committed Sep 19, 2017
2 parents ccd3059 + a9fdc9b commit 8eb8f29
Show file tree
Hide file tree
Showing 15 changed files with 188 additions and 41 deletions.
2 changes: 1 addition & 1 deletion php/WP_CLI/Bootstrap/DefineProtectedCommands.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public function process( BootstrapState $state ) {
private function get_protected_commands() {
return array(
'cli info',
'package',
'package',
);
}

Expand Down
6 changes: 3 additions & 3 deletions php/class-wp-cli.php
Original file line number Diff line number Diff line change
Expand Up @@ -381,9 +381,9 @@ private static function wp_hook_build_unique_id( $tag, $function, $priority ) {
* @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 {
* @param string $name Name for the command (e.g. "post list" or "site empty").
* @param callable $callable Command implementation as a class, function or closure.
* @param array $args {
* Optional. An associative array with additional registration parameters.
*
* @type callable $before_invoke Callback to execute before invoking the command.
Expand Down
35 changes: 22 additions & 13 deletions php/commands/help.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,20 +60,28 @@ private static function show_help( $command ) {
$wordwrap_width = \cli\Shell::columns();

// Wordwrap with indent.
$out = preg_replace_callback( '/^( *)([^\n]+)\n/m', function ( $matches ) use ( $wordwrap_width ) {
return $matches[1] . str_replace( "\n", "\n{$matches[1]}", wordwrap( $matches[2], $wordwrap_width - strlen( $matches[1] ) ) ) . "\n";
}, $out );
$out = preg_replace_callback(
'/^( *)([^\n]+)\n/m',
function ( $matches ) use ( $wordwrap_width ) {
return $matches[1] . str_replace( "\n", "\n{$matches[1]}", wordwrap( $matches[2], $wordwrap_width - strlen( $matches[1] ) ) ) . "\n";
},
$out
);

if ( $subcommands ) {
// Wordwrap with column indent.
$subcommands = preg_replace_callback( '/^(' . $column_subpattern . ')([^\n]+)\n/m', function ( $matches ) use ( $wordwrap_width, $tab ) {
// Need to de-tab for wordwrapping to work properly.
$matches[1] = str_replace( "\t", $tab, $matches[1] );
$matches[2] = str_replace( "\t", $tab, $matches[2] );
$padding_len = strlen( $matches[1] );
$padding = str_repeat( ' ', $padding_len );
return $matches[1] . str_replace( "\n", "\n$padding", wordwrap( $matches[2], $wordwrap_width - $padding_len ) ) . "\n";
}, $subcommands );
$subcommands = preg_replace_callback(
'/^(' . $column_subpattern . ')([^\n]+)\n/m',
function ( $matches ) use ( $wordwrap_width, $tab ) {
// Need to de-tab for wordwrapping to work properly.
$matches[1] = str_replace( "\t", $tab, $matches[1] );
$matches[2] = str_replace( "\t", $tab, $matches[2] );
$padding_len = strlen( $matches[1] );
$padding = str_repeat( ' ', $padding_len );
return $matches[1] . str_replace( "\n", "\n$padding", wordwrap( $matches[2], $wordwrap_width - $padding_len ) ) . "\n";
},
$subcommands
);

// Put subcommands back.
$out = str_replace( $subcommands_header, $subcommands, $out );
Expand Down Expand Up @@ -111,7 +119,7 @@ private static function pass_through_pager( $out ) {
}

// convert string to file handle
$fd = fopen( "php://temp", "r+" );
$fd = fopen( 'php://temp', 'r+' );
fputs( $fd, $out );
rewind( $fd );

Expand Down Expand Up @@ -171,8 +179,9 @@ private static function get_max_len( $strings ) {
$max_len = 0;
foreach ( $strings as $str ) {
$len = strlen( $str );
if ( $len > $max_len )
if ( $len > $max_len ) {
$max_len = $len;
}
}

return $max_len;
Expand Down
38 changes: 19 additions & 19 deletions php/commands/src/CLI_Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ public 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'] ) {
} elseif ( 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." );
}
Expand Down Expand Up @@ -244,22 +244,22 @@ public function check_update( $_, $assoc_args ) {
*/
public function update( $_, $assoc_args ) {
if ( ! Utils\inside_phar() ) {
WP_CLI::error( "You can only self-update Phar files." );
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 ) ) );
WP_CLI::error( sprintf( '%s is not writable by current user.', $old_phar ) );
} elseif ( ! 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' ) ) {
} elseif ( 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';
Expand All @@ -283,7 +283,7 @@ public function update( $_, $assoc_args ) {

WP_CLI::log( sprintf( 'Downloading from %s...', $download_url ) );

$temp = \WP_CLI\Utils\get_temp_dir() . uniqid('wp_') . '.phar';
$temp = \WP_CLI\Utils\get_temp_dir() . uniqid( 'wp_' ) . '.phar';

$headers = array();
$options = array(
Expand Down Expand Up @@ -320,18 +320,18 @@ 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.

if ( false === @rename( $temp, $old_phar ) ) {
WP_CLI::error( sprintf( "Cannot move %s to %s", $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' ) ) {
} elseif ( Utils\get_flag_value( $assoc_args, 'stable' ) ) {
$updated_version = 'the latest stable release';
} else {
$updated_version = $newest['version'];
Expand Down Expand Up @@ -359,7 +359,7 @@ private function get_updates( $assoc_args ) {
$response = Utils\http_request( 'GET', $url, null, $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 );
Expand Down Expand Up @@ -393,13 +393,13 @@ private function get_updates( $assoc_args ) {
);
}

foreach( $updates as $type => $value ) {
foreach ( $updates as $type => $value ) {
if ( empty( $value ) ) {
unset( $updates[ $type ] );
}
}

foreach( array( 'major', 'minor', 'patch' ) as $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;
}
Expand All @@ -409,7 +409,7 @@ private function get_updates( $assoc_args ) {
$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 ) );
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 ) {
Expand Down Expand Up @@ -467,12 +467,12 @@ function param_dump( $_, $assoc_args ) {
$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];
if ( isset( $config[0][ $key ] ) ) {
$current = $config[0][ $key ];
} else {
$current = NULL;
$current = null;
}
$spec[$key]['current'] = $current;
$spec[ $key ]['current'] = $current;
}
}

Expand Down Expand Up @@ -566,7 +566,7 @@ public function alias( $_, $assoc_args ) {
*/
private function get_update_type_str( $assoc_args ) {
$update_type = ' ';
foreach( array( 'major', 'minor', 'patch' ) as $type ) {
foreach ( array( 'major', 'minor', 'patch' ) as $type ) {
if ( true === \WP_CLI\Utils\get_flag_value( $assoc_args, $type ) ) {
$update_type = ' ' . $type . ' ';
break;
Expand Down
111 changes: 106 additions & 5 deletions php/utils.php
Original file line number Diff line number Diff line change
Expand Up @@ -908,24 +908,125 @@ function isPiped() {
* 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.
* @param int $flags Optional. Flags to pass to glob. Defaults to GLOB_BRACE.
*
* @return array Expanded paths.
*/
function expand_globs( $paths, $flags = GLOB_BRACE ) {
function expand_globs( $paths, $flags = 'default' ) {
// Compatibility for systems without GLOB_BRACE.
$glob_func = 'glob';
if ( 'default' === $flags ) {
if ( ! defined( 'GLOB_BRACE' ) || getenv( 'WP_CLI_TEST_EXPAND_GLOBS_NO_GLOB_BRACE' ) ) {
$glob_func = 'WP_CLI\Utils\glob_brace';
} else {
$flags = GLOB_BRACE;
}
}

$expanded = array();

foreach ( (array) $paths as $path ) {
$matching = array( $path );

if ( preg_match( '/[' . preg_quote( '*?[]{}!', '/' ) . ']/', $path ) ) {
$matching = glob( $path, $flags ) ?: array();
$matching = $glob_func( $path, $flags ) ?: array();
}

$expanded = array_merge( $expanded, $matching );
}

return array_unique( $expanded );
return array_values( array_unique( $expanded ) );
}

/**
* Simulate a `glob()` with the `GLOB_BRACE` flag set. For systems (eg Alpine Linux) built against a libc library (eg https://www.musl-libc.org/) that lacks it.
* Copied and adapted from Zend Framework's `Glob::fallbackGlob()` and Glob::nextBraceSub()`.
*
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*
* @param string $pattern Filename pattern.
* @param void $dummy_flags Not used.
*
* @return array Array of paths.
*/
function glob_brace( $pattern, $dummy_flags = null ) {

static $next_brace_sub;
if ( ! $next_brace_sub ) {
// Find the end of the subpattern in a brace expression.
$next_brace_sub = function ( $pattern, $current ) {
$length = strlen( $pattern );
$depth = 0;

while ( $current < $length ) {
if ( '\\' === $pattern[ $current ] ) {
if ( ++$current === $length ) {
break;
}
$current++;
} else {
if ( ( '}' === $pattern[ $current ] && $depth-- === 0 ) || ( ',' === $pattern[ $current ] && 0 === $depth ) ) {
break;
} elseif ( '{' === $pattern[ $current++ ] ) {
$depth++;
}
}
}

return $current < $length ? $current : null;
};
}

$length = strlen( $pattern );

// Find first opening brace.
for ( $begin = 0; $begin < $length; $begin++ ) {
if ( '\\' === $pattern[ $begin ] ) {
$begin++;
} elseif ( '{' === $pattern[ $begin ] ) {
break;
}
}

// Find comma or matching closing brace.
if ( null === ( $next = $next_brace_sub( $pattern, $begin + 1 ) ) ) {
return glob( $pattern );
}

$rest = $next;

// Point `$rest` to matching closing brace.
while ( '}' !== $pattern[ $rest ] ) {
if ( null === ( $rest = $next_brace_sub( $pattern, $rest + 1 ) ) ) {
return glob( $pattern );
}
}

$paths = array();
$p = $begin + 1;

// For each comma-separated subpattern.
do {
$subpattern = substr( $pattern, 0, $begin )
. substr( $pattern, $p, $next - $p )
. substr( $pattern, $rest + 1 );

if ( ( $result = glob_brace( $subpattern ) ) ) {
$paths = array_merge( $paths, $result );
}

if ( '}' === $pattern[ $next ] ) {
break;
}

$p = $next + 1;
$next = $next_brace_sub( $pattern, $p );
} while ( null !== $next );

return array_values( array_unique( $paths ) );
}

/**
Expand Down
Empty file added tests/data/expand_globs/bar.ab1
Empty file.
Empty file added tests/data/expand_globs/bar.ab2
Empty file.
Empty file added tests/data/expand_globs/baz.ab1
Empty file.
Empty file added tests/data/expand_globs/baz.ac1
Empty file.
Empty file.
Empty file added tests/data/expand_globs/foo.ab1
Empty file.
Empty file added tests/data/expand_globs/foo.ab2
Empty file.
Empty file.
Empty file.
37 changes: 37 additions & 0 deletions tests/test-utils.php
Original file line number Diff line number Diff line change
Expand Up @@ -494,4 +494,41 @@ public function dataPastTenseVerb() {
);
}

/**
* @dataProvider dataExpandGlobs
*/
public function testExpandGlobs( $path, $expected ) {
$expand_globs_no_glob_brace = getenv( 'WP_CLI_TEST_EXPAND_GLOBS_NO_GLOB_BRACE' );

$dir = __DIR__ . '/data/expand_globs/';
$expected = array_map( function ( $v ) use ( $dir ) { return $dir . $v; }, $expected );

putenv( 'WP_CLI_TEST_EXPAND_GLOBS_NO_GLOB_BRACE=0' );
$out = Utils\expand_globs( $dir . $path );
$this->assertSame( $expected, $out );

putenv( 'WP_CLI_TEST_EXPAND_GLOBS_NO_GLOB_BRACE=1' );
$out = Utils\expand_globs( $dir . $path );
$this->assertSame( $expected, $out );

putenv( false === $expand_globs_no_glob_brace ? 'WP_CLI_TEST_EXPAND_GLOBS_NO_GLOB_BRACE' : "WP_CLI_TEST_EXPAND_GLOBS_NO_GLOB_BRACE=$expand_globs_no_glob_brace" );
}

public function dataExpandGlobs() {
// Files in "data/expand_globs": foo.ab1, foo.ab2, foo.efg1, foo.efg2, bar.ab1, bar.ab2, baz.ab1, baz.ac1, baz.efg2.
return array(
array( 'foo.ab1', array( 'foo.ab1' ) ),
array( '{foo,bar}.ab1', array( 'foo.ab1', 'bar.ab1' ) ),
array( '{foo,baz}.a{b,c}1', array( 'foo.ab1', 'baz.ab1' , 'baz.ac1' ) ),
array( '{foo,baz}.{ab,ac}1', array( 'foo.ab1', 'baz.ab1' , 'baz.ac1' ) ),
array( '{foo,bar}.{ab1,efg1}', array( 'foo.ab1', 'foo.efg1', 'bar.ab1' ) ),
array( '{foo,bar,baz}.{ab,ac,efg}1', array( 'foo.ab1', 'foo.efg1', 'bar.ab1', 'baz.ab1', 'baz.ac1' ) ),
array( '{foo,ba{r,z}}.ab1', array( 'foo.ab1', 'bar.ab1', 'baz.ab1' ) ),
array( '{foo,ba{r,z}}.{ab1,efg1}', array( 'foo.ab1', 'foo.efg1', 'bar.ab1', 'baz.ab1') ),
array( '{foo,bar}.{ab{1,2},efg1}', array( 'foo.ab1', 'foo.ab2', 'foo.efg1', 'bar.ab1', 'bar.ab2' ) ),
array( '{foo,ba{r,z}}.{a{b,c}{1,2},efg{1,2}}', array( 'foo.ab1', 'foo.ab2', 'foo.efg1', 'foo.efg2', 'bar.ab1', 'bar.ab2', 'baz.ab1', 'baz.ac1', 'baz.efg2' ) ),

array( 'no_such_file', array( 'no_such_file' ) ), // Documenting this behaviour here, which is odd (though advertized) - more natural to return an empty array.
);
}
}

0 comments on commit 8eb8f29

Please sign in to comment.