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

Conflict-free distribution - current state and issues that need solving #5920

Open
schlessera opened this issue Mar 15, 2024 · 2 comments
Open

Comments

@schlessera
Copy link
Member

For the moment, if you pull in WP-CLI as a dependency in your project, WP-CLI's sub-dependencies can conflict with your project's other dependencies.

Topic A: Namespace Scoping

In the PHP/Composer world, you'd solve this by scoping the namespace of all of WP-CLI's dependencies to get around namespace collisions, so you are able to pull in potentially different versions of a same dependency. This can be done at the source level, or it can be done during a build step to adapt the Phar file instead.

This approach generally works fine for development tools that are pulled in via Composer and that are stand-alone executables. However, this is not the case for WP-CLI.

When you use WP-CLI, it will execute the entire WordPress stack it s being used on, including all active plugins and themes. And plugins or themes can extend WP-CLI to add custom commands or to hook into the execution to modify the behavior of any of the WP-CLI logic.

This means that, if we scope the namespace of some of the internals of WP-CLI, and those happen to be used by plugins or themes directly in their extension, this will trigger fatal errors.

So we'll need to discuss if this is a real problem or not, and what potential solutions to this might be. One approach might be to add a backwards-compatible fallback autoloader that intercepts calls to non-scoped classes and does something like adding class aliases or similar. This is a nasty hack, but that's how we roll in the WordPress world anyway.

Topic B: Shim VS requirements

Also, to make things cleaner, we'd want to properly wrap everything up in a Composer shim package that only pulls in the Phar file, instead of the full source repository. This will have benefits for download size/speed, IDE indexing, etc...

However, we'd want to state in the composer.json file of the shim package how it relates to dependents and dependencies. This is not easy to do, though, given the historical baggage that WP-CLI brings to the table.

We don't want to have the shim be pulled in by one plugin and the source version pulled in by another plugin, for example.

The proper way to do this with Composer would be to have a virtual package, and then have both the source and the Phar versions provide that virtual package. This way, you can require "any" implementation of WP-CLI and don't care how it was actually packaged. However, that would require a major change and everyone would need to adapt their dependency requirements.

Right now, there are a few ways how people can pull in WP-CLI via Composer, and each of these would need a different solution to resolve this:

  • pulling in the framework to be able to add a custom command: require: "wp-cli/wp-cli"
  • pulling in the bundle to have all WP-CLI default commands available: require "wp-cli/wp-cli-bundle"
  • pulling in the specific command(s) you need for your project: require "wp-cli/db-command"

This would mean that - in the absence of a multitude of virtual packages - the composer.json file for the shim package would need a multitude of replace statements for each of the bundled packages as well as for wp-cli/wp-cli-bundle itself.

However, I'm not fully sure this will not have unwanted side-effects as regards to a plugin for example that has wp-cli/wp-cli as a dependency.

So, above are the two topics we need more discussion about to solve dependency conflicts with WP-CLI in Composer stacks, and I'll greatly appreciate any insights that the community can share on this.

@ju1ius
Copy link

ju1ius commented Mar 26, 2024

Hi,

Let us start by the easiest issue:

we'd want to properly wrap everything up in a Composer shim package that only pulls in the Phar file, instead of the full source repository.

You absolutely don't need to put the full source repository inside a composer package.
Just add an export-ignore field in the .gitattributes file of the repository for each file or directory that should be excluded from the github tarball.

For example the .gitattributes for wp-cli/wp-cli should look like this:

# Auto detect text files and perform EOL normalization
* text=auto eol=lf
tests/data/*-win.php eol=crlf

# Don't show bundled libraries as source files in GitHub
bundle/**/* linguist-vendored

# Exclude config/build/test files from archive
/features         export-ignore
/tests            export-ignore
/.actrc           export-ignore
/.editorconfig    export-ignore
/.gitattributes   export-ignore
/.gitignore       export-ignore
/.mailmap         export-ignore
/behat.yml        export-ignore
/phpcs.xml.dist   export-ignore
/phpunit.xml.dist export-ignore

References:

@BrianHenryIE
Copy link
Member

we'll need to discuss if this is a real problem or not

I think when I am developing a plugin and I install WP CLI via Composer, I want the true source of it and its dependencies available to me in the IDE. When installing the phar, having the dependencies scoped makes a lot of sense.

The PHPUnit maintainer advocates for using phars for dev tools and only use Composer for production dependencies:

https://docs.phpunit.de/en/11.1/installation.html#phar-or-composer

The virtual packages solution seems complex for a problem that users have opted into themselves. The wp-cli/wp-cli-shim package (once scoped) seems like the perfect alternative for people.

What would happen with the global phar and wp package install? I think maybe the scoping tool might need to be included with WP CLI and run as part of each package install.

a plugin for example that has wp-cli/wp-cli as a dependency.

Is it ever correct for a plugin to require wp-cli/wp-cli? I require it --dev and see it as "provided", and check the class is present before adding commands.

I maintain the scoping tool: https://github.com/BrianHenryIE/strauss

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants