Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use custom autoloader to load framework #5010

Merged
merged 6 commits into from Dec 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
188 changes: 159 additions & 29 deletions features/bootstrap.feature
@@ -1,5 +1,12 @@
Feature: Bootstrap WP-CLI

Background:
When I run `wp package path`
And save STDOUT as {PACKAGE_PATH}
And I run `rm -rf {PACKAGE_PATH}/vendor`
And I run `rm -rf {PACKAGE_PATH}/composer.json`
And I run `rm -rf {PACKAGE_PATH}/composer.lock`

@require-opcache-save-comments
Scenario: Basic Composer stack
Given an empty directory
Expand All @@ -23,7 +30,7 @@ Feature: Bootstrap WP-CLI
"""

Scenario: Composer stack with override requirement before WP-CLI
Given an empty directory
Given a WP installation
And a composer.json file:
"""
{
Expand All @@ -34,19 +41,19 @@ Feature: Bootstrap WP-CLI
"repositories": [
{
"type": "path",
"url": "./cli-override-command",
"url": "./override",
"options": {
"symlink": false
}
}
],
"require": {
"wp-cli/cli-override-command": "*",
"wp-cli/override": "*",
"wp-cli/wp-cli": "dev-master"
}
}
"""
And a cli-override-command/cli.php file:
And a override/override.php file:
"""
<?php
if ( ! class_exists( 'WP_CLI' ) ) {
Expand All @@ -56,9 +63,12 @@ Feature: Bootstrap WP-CLI
if ( file_exists( $autoload ) && ! class_exists( 'CLI_Command' ) ) {
require_once $autoload;
}
// Override framework command.
WP_CLI::add_command( 'cli', 'CLI_Command', array( 'when' => 'before_wp_load' ) );
// Override bundled command.
WP_CLI::add_command( 'eval', 'Eval_Command', array( 'when' => 'before_wp_load' ) );
"""
And a cli-override-command/src/CLI_Command.php file:
And a override/src/CLI_Command.php file:
"""
<?php
class CLI_Command extends WP_CLI_Command {
Expand All @@ -67,18 +77,28 @@ Feature: Bootstrap WP-CLI
}
}
"""
And a cli-override-command/composer.json file:
And a override/src/Eval_Command.php file:
"""
<?php
class Eval_Command extends WP_CLI_Command {
public function __invoke() {
WP_CLI::success( "WP-Override-Eval" );
}
}
"""
And a override/composer.json file:
"""
{
"name": "wp-cli/cli-override-command",
"description": "A command that overrides the bundled 'cli' command.",
"name": "wp-cli/override",
"description": "A command that overrides the bundled 'cli' and 'eval' commands.",
"autoload": {
"psr-4": { "": "src/" },
"files": [ "cli.php" ]
"files": [ "override.php" ]
},
"extra": {
"commands": [
"cli"
"cli",
"eval"
]
}
}
Expand All @@ -91,10 +111,95 @@ Feature: Bootstrap WP-CLI
Success: WP-Override-CLI
"""

When I run `vendor/bin/wp eval '\WP_CLI::Success( "WP-Standard-Eval" );'`
Then STDOUT should contain:
"""
Success: WP-Override-Eval
"""

Scenario: Override command bundled with current source

Given an empty directory
And a cli-override-command/cli.php file:
Given a WP installation
And a override/override.php file:
"""
<?php
if ( ! class_exists( 'WP_CLI' ) ) {
return;
}
$autoload = dirname( __FILE__ ) . '/vendor/autoload.php';
if ( file_exists( $autoload ) && ! class_exists( 'CLI_Command' ) ) {
require_once $autoload;
}
// Override framework command.
WP_CLI::add_command( 'cli', 'CLI_Command', array( 'when' => 'before_wp_load' ) );
// Override bundled command.
WP_CLI::add_command( 'eval', 'Eval_Command', array( 'when' => 'before_wp_load' ) );
"""
And a override/src/CLI_Command.php file:
"""
<?php
class CLI_Command extends WP_CLI_Command {
public function version() {
WP_CLI::success( "WP-Override-CLI" );
}
}
"""
And a override/src/Eval_Command.php file:
"""
<?php
class Eval_Command extends WP_CLI_Command {
public function __invoke() {
WP_CLI::success( "WP-Override-Eval" );
}
}
"""
And a override/composer.json file:
"""
{
"name": "wp-cli/override",
"description": "A command that overrides the bundled 'cli' and 'eval' commands.",
"autoload": {
"psr-4": { "": "src/" },
"files": [ "override.php" ]
},
"extra": {
"commands": [
"cli",
"eval"
]
}
}
"""
And I run `composer install --working-dir={RUN_DIR}/override --no-interaction 2>&1`

When I run `wp cli version`
Then STDOUT should contain:
"""
WP-CLI
"""

When I run `wp eval '\WP_CLI::Success( "WP-Standard-Eval" );'`
Then STDOUT should contain:
"""
Success: WP-Standard-Eval
"""

When I run `wp --require=override/override.php cli version`
Then STDOUT should contain:
"""
WP-Override-CLI
"""

When I run `wp --require=override/override.php eval '\WP_CLI::Success( "WP-Standard-Eval" );'`
Then STDOUT should contain:
"""
Success: WP-Override-Eval
"""

Scenario: Override command through package manager

Given a WP installation
And a override/override.php file:
"""
<?php
if ( ! class_exists( 'WP_CLI' ) ) {
Expand All @@ -104,9 +209,12 @@ Feature: Bootstrap WP-CLI
if ( file_exists( $autoload ) && ! class_exists( 'CLI_Command' ) ) {
require_once $autoload;
}
// Override framework command.
WP_CLI::add_command( 'cli', 'CLI_Command', array( 'when' => 'before_wp_load' ) );
// Override bundled command.
WP_CLI::add_command( 'eval', 'Eval_Command', array( 'when' => 'before_wp_load' ) );
"""
And a cli-override-command/src/CLI_Command.php file:
And a override/src/CLI_Command.php file:
"""
<?php
class CLI_Command extends WP_CLI_Command {
Expand All @@ -115,35 +223,57 @@ Feature: Bootstrap WP-CLI
}
}
"""
And a cli-override-command/composer.json file:
And a override/src/Eval_Command.php file:
"""
<?php
class Eval_Command extends WP_CLI_Command {
public function __invoke() {
WP_CLI::success( "WP-Override-Eval" );
}
}
"""
And a override/composer.json file:
"""
{
"name": "wp-cli/cli-override",
"description": "A command that overrides the bundled 'cli' command.",
"name": "wp-cli/override",
"description": "A command that overrides the bundled 'cli' and 'eval' commands.",
"autoload": {
"psr-4": { "": "src/" },
"files": [ "cli.php" ]
"files": [ "override.php" ]
},
"extra": {
"commands": [
"cli"
"cli",
"eval"
]
}
}
"""
And I run `composer install --working-dir={RUN_DIR}/cli-override-command --no-interaction 2>&1`
And I run `wp package install {RUN_DIR}/override`

When I run `wp cli version --skip-packages`
Then STDOUT should contain:
"""
WP-CLI
"""

When I run `wp eval '\WP_CLI::Success( "WP-Standard-Eval" );' --skip-packages`
Then STDOUT should contain:
"""
Success: WP-Standard-Eval
"""

When I run `wp cli version`
Then STDOUT should contain:
"""
WP-CLI
"""

When I run `wp --require=cli-override-command/cli.php cli version`
Then STDOUT should contain:
"""
WP-Override-CLI
"""
Then STDOUT should contain:
"""
WP-Override-CLI
"""

When I run `wp eval '\WP_CLI::Success( "WP-Standard-Eval" );'`
Then STDOUT should contain:
"""
Success: WP-Override-Eval
"""

Scenario: Composer stack with both WordPress and wp-cli as dependencies (command line)
Given a WP installation with Composer
Expand Down
68 changes: 33 additions & 35 deletions php/WP_CLI/Bootstrap/IncludeFrameworkAutoloader.php
Expand Up @@ -2,57 +2,55 @@

namespace WP_CLI\Bootstrap;

use WP_CLI\Autoloader;

/**
* Class IncludeFrameworkAutoloader.
*
* Loads the framework autoloader that is provided through the `composer.json`
* file.
* Loads the framework autoloader through an autolaoder separate from the
* Composer one, to avoid coupling the loading of the framework with bundled
* commands.
*
* This only contains classes for the framework.
*
* @package WP_CLI\Bootstrap
*/
final class IncludeFrameworkAutoloader extends AutoloaderStep {
final class IncludeFrameworkAutoloader implements BootstrapStep {

/**
* Get the autoloader paths to scan for an autoloader.
* Process this single bootstrapping step.
*
* @param BootstrapState $state Contextual state to pass into the step.
*
* @return string[]|false Array of strings with autoloader paths, or false
* to skip.
* @return BootstrapState Modified state to pass to the next step.
*/
protected function get_autoloader_paths() {
$autoloader_paths = array(
WP_CLI_VENDOR_DIR . '/autoload.php',
);

if ( $custom_vendor = $this->get_custom_vendor_folder() ) {
array_unshift(
$autoloader_paths,
WP_CLI_ROOT . '/../../../' . $custom_vendor . '/autoload.php'
public function process( BootstrapState $state ) {
if ( ! class_exists( 'WP_CLI\Autolaoder' ) ) {
require_once WP_CLI_ROOT . '/php/WP_CLI/Autoloader.php';
}

$autoloader = new Autoloader();

$mappings = [
'WP_CLI' => WP_CLI_ROOT . '/php/WP_CLI',
'cli' => WP_CLI_VENDOR_DIR . '/wp-cli/php-cli-tools/lib/cli',
'Requests' => WP_CLI_VENDOR_DIR . '/rmccue/requests/library/Requests',
'Symfony\Component\Finder' => WP_CLI_VENDOR_DIR . '/symfony/finder/',
];

foreach ( $mappings as $namespace => $folder ) {
$autoloader->add_namespace(
$namespace,
$folder
);
}

\WP_CLI::debug(
sprintf(
'Framework autoloader paths: %s',
implode( ', ', $autoloader_paths )
),
'bootstrap'
);
include_once WP_CLI_VENDOR_DIR . '/rmccue/requests/library/Requests.php';
include_once WP_CLI_VENDOR_DIR . '/ramsey/array_column/src/array_column.php';
include_once WP_CLI_VENDOR_DIR . '/wp-cli/mustangostang-spyc/Spyc.php';

return $autoloader_paths;
}
$autoloader->register();

/**
* Handle the failure to find an autoloader.
*
* @return void
*/
protected function handle_failure() {
fwrite(
STDERR,
"Internal error: Can't find Composer autoloader.\nTry running: composer install\n"
);
exit( 3 );
return $state;
}
}