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

Command ecosystem #572

Closed
xendk opened this issue Apr 11, 2014 · 59 comments
Closed

Command ecosystem #572

xendk opened this issue Apr 11, 2014 · 59 comments

Comments

@xendk
Copy link
Contributor

xendk commented Apr 11, 2014

Having written a few Drush commands, I've repeatedly run into the problem of how/where to host/release them.

Github being the first obvious choice, it's quick, you can run tests on Travis, and seems natural as Drush itself is here.

However, Drupal.org does have the very nice advantage of supporting drush dl <drush_command>.

Basically, what I'd really like would be being able to tell people to drush dl <something> a Github hosted command.

I guess that it's quite doable to make Drush understand drush dl xendk/bandaid, and do some Github magic, or implement a drush extend xendk/bandaid, but what's the Drush core teams thoughts?

@weitzman
Copy link
Member

Makes sense to me. My one hesitation is that we are somewhat duplicating what composer does. We have to think about how Drush (and Drupal) use Composer. That doesn't have to block better github integration. Maybe dl could assume Github is the project name contains a slash.

@xendk
Copy link
Contributor Author

xendk commented Apr 11, 2014

Well, for one I assume that Drush commands downloaded from Github might use composer to install their dependencies.

In general, I don't think the average user would use composer to manage their Drush commands, but that doesn't mean that Drush couldn't use it internally.

But if we rely on composer, the question whether to use packagist or something arises. It would be nice to have some standard repository for Drush commands. As it is, they're pretty much unfindable on d.o, nevermind the double work of maintaining a project on d.o too.

@weitzman
Copy link
Member

I would love to ask all drush commandfiles to include a composer.json with a keyword=drush and list themselves on packagist. unfortunately, i don't see a way on Packagist to list all packages that have a given keyword. It might be that Drush should host its own plugin directory. I might be interested in that. Github webhooks make that not overly difficult.

@weitzman
Copy link
Member

Actually, Packagist does have a decent search API.

The listings are ugly still, unfortunately.

@xendk
Copy link
Contributor Author

xendk commented Apr 11, 2014

We could make our own nice plugin directory just by using the services of packagist. For listing: https://packagist.org/search.json?tags[]=drush

And https://packagist.org/packages/drush/drush.json gives pretty much the info we need, I think.

So, I figure that it shouldn't be that hard to implement a packages.drush.org that simply asks packagist and renderes the result nicely. My boss might even throw some designer/themer hours after it just for the fun of it. At least we could make a drush command to get the listing and pretty print the result of second .

I'll look into how difficult it would be making drush dl understand packagist vendor/project.

@weitzman
Copy link
Member

  1. Love that listing URL! Perhaps we do a static HTML page that consumes listing JSON and builds a table view from it. The detail for each row would point to Github or packagist. Grunt does something similar, using NPM as data source. Hopefully your designer can do better than Grunt :)
  2. dl command is heavily based on drupal.org's updatexml which has no analogue at Github. On Github, a projects supports multiple versions of Drupal in the same directory, naming commandfiles so they only apply to one version. Not sure how to proceed here. Maybe we shell out to a different command like composer or git. Requires some experimentation.

@xendk
Copy link
Contributor Author

xendk commented Apr 13, 2014

Ok, I don't understand point 2. Multiple versions of Drupal in the same directory?

@weitzman
Copy link
Member

I said that poorly. I think the best practice for Github Drush projects will be files like

  1. rules.d8.drush.inc
  2. rules.d7.drush.inc
  3. rules.inc (contains shared code, when needed)

@xendk
Copy link
Contributor Author

xendk commented Apr 13, 2014

I still don't understand the issue, I must be missing something.

For Drush commands related to a module (like rules), the command files
would be included with the module installed on the site, and therefore the
right version. Modules are still installed from d.o.

For other Drush commands, they're basically version independent per
default, though some commands might ask Drush for the version of the
current site, if they need to be specific. And in extreme cases implement
something like what you said internally.

So I don't see the need for versioning commands on Github or packagist?
On Apr 13, 2014 5:36 PM, "Moshe Weitzman" [email protected] wrote:

I said that poorly. I think the best practice for Github Drush projects
will be files like

  1. rules.d8.drush.inc
  2. rules.d7.drush.inc
  3. rules.inc (contains shared code, when needed)

Reply to this email directly or view it on GitHubhttps://github.com//issues/572#issuecomment-40310483
.

@weitzman
Copy link
Member

OK, I guess I am making this excessively complicated. My concerns make more sense for modules that choose to move to Github and not push their code+releases back to drupal.org. Maybe we don't have to worry about those in this issue.

Looking at commands/pm/download.pm.inc, it is pretty awkward IMO hack in downloading of Github projects. I think it would be better if folks edited the composer.json that comes with Drush and ran composer update. We could provide an choice in drush conf that would open composer.json in a $EDITOR for you. Good solution?

@xendk
Copy link
Contributor Author

xendk commented Apr 14, 2014

One could argue that modules belong on d.o anyway, so I'd say we can ignore
that for the moment being.

I don't like the composer.json way, it requires that any random Drush
newbie that wants to install a Drush command suddenly needs to understand
composer.json syntax and composer. I was aiming at being able to specify a
oneliner in a readme in order to install an extension. Hence the idea of
extending the existing dl command which is already used for d.o hosted
commands.

One could argue for a new extension management command, but then it should
really support both Github and d.o hosted commands, to keep confusion to a
minimum.

Keeping things simple both from a code and end-user perspective might be
difficult here.
On Apr 14, 2014 9:54 PM, "Moshe Weitzman" [email protected] wrote:

OK, I guess I am making this excessively complicated. My concerns make
more sense for modules that choose to move to Github and not push their
code+releases back to drupal.org. Maybe we don't have to worry about
those in this issue.

Looking at commands/pm/download.pm.inc, it is pretty awkward IMO hack in
downloading of Github projects. I think it would be better if folks edited
the composer.json that comes with Drush and ran composer update. We could
provide an choice in drush conf that would open composer.json in a
$EDITOR for you. Good solution?


Reply to this email directly or view it on GitHubhttps://github.com//issues/572#issuecomment-40410319
.

@weitzman
Copy link
Member

I haven't perused it all, but the wp-cli tool has something called Community Packages which can be installed with composer, among other ways https://github.com/wp-cli/wp-cli/wiki/Community-Packages

@xendk
Copy link
Contributor Author

xendk commented Apr 19, 2014

I've had some time to look a bit more at composer, and using a composer.json file (rather than Drushs, which gets overwritten when you upgrade Drush) could be the way.

As it is now, one can go cd ~/.drush && composer require <some-drush-command>:* and it can install a custom Drush command from Packagist. I don't know if Drush is recursive enough to discover commands inside .drush/vendor, but I guess that could be fixed.

It means that we're leaving d.o hosted Drush commands in the dust, but that's up to the Drush team to decide. Personally, I think it's fair enough as it's only pure Drush commands that's affected (coder module being the odd case suggesting to install the module in .drush, but even that have a composer version now).

We could make a thin Drush wrapper for the composer require call, to make it seem like Drush have a build in package manager, on the other hand, as composer is already the preferred way to install Drush, we might as well not. As long as packages.drush.org and/or a drush list-extensions command explains what composer command lines to invoke, anyone should be able to follow.

Any thoughts?

@weitzman
Copy link
Member

We are in perfect agreement.

  1. We do have to do something to get Drush to recognize commands downloaded via composer. I'm warming up to the ideas proposed at Leverage symfony/console package #88, FWIW. Not sure if thats totally relevant though. This is a pretty critical issue, so lets talk through how this should work. Note that Composer can install Drush locally to a project or globally to a server.
  2. Wrapping composer is currently offerred by https://drupal.org/project/composer. I haven't used this project yet. It makes sense in Drush core, only if the wrapper adds value beyond what composer does.

@xendk
Copy link
Contributor Author

xendk commented Apr 21, 2014

Good. :-)

  1. Leverage symfony/console package #88 is interesting, but as I read it it still depends on hook_drush_command for the discovery. Unless they bake in some auto-discovery of DrushCommand subclasses. What do you mean by "Composer can install Drush locally to a project"? What is a project? A full Drupal? Or basically anything (I can see that you can add Drush to any composer.json you might wish, but fail to see what for).

Anyway, it should work as it is. I just checked, and Drush uses drush_scan_directory() to find command files, which mean that even though the command file lies below .drush/vendor/xendk/bandaid, it should find it just fine. Unless things are drastically changed in #88, this should just continue to work.

  1. As far as I can tell, https://drupal.org/project/composer is just a thin wrapper around composer. I'll make the same argument as against making a specific extension install command. If we're just using composer, lets just use composer, and not confuse anybody by introducing a new command which is just composer.

I'll try making a packagist package of a Drush command and see how/if it works.

@weitzman
Copy link
Member

Yes, I think some sites will add Drush to their composer.json so that all
developers and scripts are using the same exact drush version. I used to
think this was crazy but Composer really changed my world view. This
technique sounds smart to me now. Lately I've been thinking Drush should
optionally not search outside the current site for commandfiles, config
and site aliases. This would contain Drush to just the current
site/project. Anyway, thats for another issue.

Since you are interested in these issues, I want to draw your attention to
#524. We could use some brainpower there too :)

@xendk
Copy link
Contributor Author

xendk commented Apr 21, 2014

I've just tried installing https://packagist.org/packages/xendk/bandaid using composer require, and it works just fine, both on master and 6.2.

So.. This issue seems to be more about documenting this as the suggested way to install drush commands, and build something that'll provide a nice listing of packagist drush commands.

"add Drush to their composer.json"... I'm not familiar with the practice of using composer for Drupal sites, so I'm not sure how things will get laid out (and how that'll affect this issue). Got a link to someone explaining the details?

@kostajh
Copy link
Contributor

kostajh commented Apr 21, 2014

I'm not sure how they did it but it seems like it could be fairly simple to set up something like https://plugins.drush.org based on http://plugins.roundcube.net/

The downside is that it's another bit of infrastructure to maintain.

@xendk
Copy link
Contributor Author

xendk commented Apr 21, 2014

@kostajh Looks like they're hosting their own version of the packagist code base. We could do that, but as you said, it's another bit of infrastructure.

We've discussed creating a plugins.drush.org as a simple wrapper that just asks packagists for packages with the drush tag, which might even be possible to do clientside. The advantage is that by using packagist, you can simply do a composer require, without having to tell composer about our custom repositiory.

@xendk
Copy link
Contributor Author

xendk commented Apr 22, 2014

Aah, I guess it shouldn't just be that easy.

So, having a command installable through composer, I figured I'd fix up its tests to work with the new autoloaded test classes.

The obvious solution would be to require-dev drush so composer would fix up the autoloading, however then we'll end up with a full Drush inside .drush/vendor, which is pretty much guaranteed to cause havoc at some point.

Of course I could work around the problem by keeping composer.json elsewhere and symlinking my commands directory into .drush, but that's rather bad DX.

@weitzman
Copy link
Member

Devel solves this with a by using the --configuration option for phpunit command. I made a wrapper script which ships with Devel - http://drupalcode.org/project/devel.git/blob/refs/heads/8.x-1.x:/run-tests-drush.sh

@xendk
Copy link
Contributor Author

xendk commented Apr 23, 2014

That fixes it.

Sidenote: With a bit of fudging, it still possible to run the same tests on Drush 5-7: xendk/bandaid@58fd7b3 which is nice.

So we're back to "green" on this issue.

@weitzman
Copy link
Member

@xendk - would be wonderful to make some progress on a listing app for Drush projects on Packagist. keep us posted!

@xendk
Copy link
Contributor Author

xendk commented May 14, 2014

Actually we have a working site, locally, that just needs to get some of the rougher edges sanded off. But then our resident themer got ill and other things took precedence, but I'll try to get it up somewhere soon.

As it is, the entire catalog is 3 extensions, where I suspect that one is dead. But that should change.

@xendk
Copy link
Contributor Author

xendk commented May 15, 2014

@xendk
Copy link
Contributor Author

xendk commented May 26, 2014

@weitzman Had time to check it out? (forgot to @mention)

@weitzman
Copy link
Member

weitzman commented Jun 8, 2014

Sorry for the delay - I lost track of this.

I'm a bit sad that the package listing is a Drupal site. Would it be possible to code up a client side version? I think it would be OK to just focus on listings and link to packagist.org for package detail.

@weitzman
Copy link
Member

weitzman commented Jun 8, 2014

Also, I got the idea from http://blog.atom.io/2014/04/25/ci-for-your-packages.html that would could document a sample travis.yml so that Drush commands can easily test themselves using our Unish test framework.

@xendk
Copy link
Contributor Author

xendk commented Jun 9, 2014

If we leave the package display up to packagist, we loose the copy-pastable command for installing (not all drush users are intimate with composer yet).

And while I get the current trend that's making people use Jekyll and the like instead of Drupal for their personal blog, I'm also a bit too old to really care. I picked Drupal as it makes sense to use something that anyone that might end up working on the site should feel at home in, and I picked D8 to be a bit ahead of the curve and try using it for something practical (I know that goes a bit agaist point one, but that's mostly a matter of time).

+1 for the CI instructions. And I'd also suggest some pages giving new users an overview of how to manage their drush commands with composer.

@greg-1-anderson
Copy link
Member

Good comments! First, my replies to @weitzman:

  1. I'll build it, but later.

  2. You are right. We should only search in the modules folders for modules (Drupal 8 requires them to be here anyway; we could also search core/modules, if anyone wanted to put Drush commands in Core, but they probably won't). The drush folder in the Drupal root is a fine place to put Drush commandfiles. If we are using a custom installer like one of the ones mentioned in my command above, then we would just need to put something like this in the composer.json file for our Drupal site:

  "extra": {
    "custom-installer": {
      "drupal-core": "core",
      "drupal-module": "modules/{$name}/",
      "drupal-theme": "themes/{$name}/",
      "drush-extension": "drush/{$name}/"
    },
  }

If we do this, then we can be sure that all Drush extensions loaded via 'composer require' will be found in the "drush" folder of the Drupal root. This will greatly limit the number of places we need to look for commandfiles.

  1. Seems useful to be able to use your old global commandfiles without copying them into your project -- but you're right, this is an optional feature.

@xendk:

You are right, the goal here is to have Drush be loaded via composer as part of each Drupal project. So, you install Drush in your Drupal project via 'composer require drush/drush', and it ends up in vendor/drush/drush. Any composer libraries brought in by Drush's composer.json file will be part of the Drupal site's autoloader.

The main reason for having a global Drush is so that you can use it for your old, pre-Composer Drupal sites. If you only have one Drupal 8 site on a machine, then just put vendor/drush/drush in your $PATH, and you're done. As Moshe said, we wouldn't have to allow global extensions to be loaded from a site-specific Drush; if we did, though, it could only be extensions that did not use Composer.

You are absolutely right about the dependency problem. For Composer libraries such as Guzzle, that are used in Core, it's easy: everyone has to use the version that Drupal requires, or you'll get a Composer error. For minor revisions, contrib module writers will have a choice. If they require very specific dependencies, then they are likely to get a lot of Composer errors as Drupal upgrades. If they are lax, then things will "just work", until they don't, and then the user will get strange errors. I expect that everyone will eventually settle on being lax for contrib, and hopefully the library writers of the world will be very good about not breaking backwards compatibility, except with a major version upgrade. Then there will be no strange errors (crossing fingers).

Major version upgrades are going to be a larger problem, especially for "discovered" libraries that are not used in Drupal core, but become very popular in contrib. If you have a bunch of modules using foo 4., and then foo 5. comes out and is adopted by some contrib modules, then Drupal users will not be able to use certain modules together. Composer will tell you when this happens, but most people won't have any recourse. If this problem is left unchecked, then a site could be blocked from applying a Drupal security update in a crisis. This would be bad.

Regardless, though, Drupal is going down this road. Drush can either follow or not; if we don't, then we're essentially saying don't use composer libraries in your Drush extensions, because they won't work. That's the worse decision, in my mind.

@xendk
Copy link
Contributor Author

xendk commented Dec 12, 2014

@greg-1-anderson
So in summary, global commandfiles will be crippled by not being able to work on a site, or use any composer libs? As one that's probably created more global than site commands, that makes me sad. You've just killed Bandaid as it definitely isn't site specific, but uses composer.

But after some internal discussions here, I don't understand the original problem. You can have two autoloaders, and they can load the same lib. Bandaid and Drush both pull in YAML, and that works fine. You do have a problem if the first registered autoloader loads a version that user of the second doesn't work with, though.

I might have been gripped by late night fatalism, but I don't think the only options are "use composer like this or not at all".

@greg-1-anderson
Copy link
Member

Haven't had time to investigate here. I was having trouble with Drush IQ's use of Goutte conflicting with Drupal 8's use of Goutte; I need to go back and see what exactly are the limitations with version matching when two autoloaders pull in the same library. I think both were using the same major version of Goutte.

I agree that ultimately, supporting global commandfiles in a non-crippled way is important. We just need to come up with the best rules and conventions for selecting library versions and including the autoloader.

@derhasi
Copy link

derhasi commented Dec 20, 2014

Stumpled upon this issue, as I want to rework my master drush command. I just read through the issue, but don't get my head around everything. So I try to summarize the uses cases we've got with Drush and composer. Currently I see the following:

  • Loading drush commands from github (something like drush dl github/xendk/bandaid) - may be obsolete with the next one
  • Loading drush commands from packagist.org (composer global require xendk/bandaid or composer require xendk/bandaid)
  • Autoload classes within a drush command package/project: (src/...) (not composer, simply autoloader issue)
  • Install and autoload dependencies of a drush command via composer (composer.json)

Before I make any (new) suggestions, can you help me out, if there are more uses cases we want to cover?

FYI: I just referenced this discussion in the meta page of our Drupal Composer group.
edit: fixed link

@ergonlogic
Copy link
Member

I echo @darthsteven's excitement for managing Drush extensions with Composer, as it should greatly simplify custom Aegir installations.

That said, I really like the idea of drush dl user/project, even if just for global drush commands. In #572 (comment), @greg-1-anderson mentions:

  1. The global Drush should also have a 'composer.json' file. Folks should install their global Drush extensions here via 'composer require'. Thanks to Packagist for Drupal Projects, it would be possible for 'drush dl foo' to become a wrapper for 'cd /drush/home && composer require drupal/foo'. The autoload file in Drush's global vendor directory is loaded iff the Drupal site that is bootstrapped does not have a composer.json, or if there is no site bootstrapped by this command.

Is that an approach the Drush maintainers would be open to? If so, I'd be happy to start working on a PR.

@weitzman
Copy link
Member

@ergonlogic - I'm open to it, but can't guarantee a merge. Wrappers have to be thin and foolproof in order to be an improvement over 'cd /drush/home && composer require drupal/foo. It would really help to have a PR, even an unpolished one.

@greg-1-anderson
Copy link
Member

Copying here a discussion that happened outside this issue (related specifically to the proposal to have a "global" Drush that finds and re-launches the site-specific Drush):

There is another alternative for finding the right Drush that I don't think is discussed here. For folks who use the 'use' command, we could make a variant that alters the PATH such that the drush that goes with the site you selected via 'use' appears first. The issue here, of course, is that you can't set one of the shell's environment variables from a subprocess, so this would only work if 'use' was a shell alias that first called 'drush use', and then set the PATH if it was necessary to do so. This could work in conjunction with a global Drush, that would appear first in the PATH when not 'use'-ing a site, or when the 'use'd site is remote.

Also, regarding the idea of one Drush calling some other Drush, this is essentially what happens already when you run 'drush @Remote cc all' -- except in this case, the local Drush uses ssh to call the remote Drush w/ a "cc all" command. In the composer case (per-site, composer-managed Drush, that is), we'd do the same thing, but we'd just call Drush directly.

@greg-1-anderson
Copy link
Member

As mentioned in #1132, I think we should standardize on using "drupal-drush" as our composer type, rather than "drush-extension".

@greg-1-anderson
Copy link
Member

I made some progress in #1138. With this PR, drush @site foo will re-launch the site-local copy of Drush associated with @site if it exists. This was really easy to do--I just used the same mechanism already in place in Drush for doing the same thing when @site is remote. The behavior of Drush does not change unless someone installs a site-local copy of Drush.

I also set the --local flag, which effectively "breaks" global Drush extensions, unless you copy them into each of your sites. However, we do not need to stop here; there are other things we can do to make global Drush extension management easier -- maybe even automatic.

I can continue in the same PR, or commit this one and continue with separate PRs for each improvement.

@greg-1-anderson
Copy link
Member

Okay, here is my new idea. This replaces most of what I suggested in 1) - 4) above, while maintaining the original vision (a) - (c).

  1. Folks can use either a global Drush, or a site-local Drush, per their preference (Redispatch to site-local drush if it exists #1138).
  2. When including Drush extensions with a site, you must use a custom autoloader that places them in ROOT/drush or ROOT/sites/all/drush. (Composer installers uses ROOT/drush, composer_generate uses David Barrat's installer and places extensions in ROOT/sites/all/drush.) This means we do not need to change the logic for how commandfiles are handled just yet.
  3. We will provide a function, drush_autoload(), that will load a Drush extension's autoload file for it. Drush will figure out whether the extension was already autoloaded, and will turn drush_autoload() into a no-op if so. This will allow composer-using Drush extensions to work regardless of whether they are included in a site's composer.json file or left independent.
  4. ~~We will change the behavior of --local so that, instead of eliminating the global locations, it will instead look for config and commandfiles in ~/.drush/shared (and so on for the other locations). Thus, whether or not you are using a site-local Drush, you can choose to install your extensions locally or globally. Just put config or commandfiles in the "shared" directory if you want them to be used in both the site-local and the global environments, and put them anywhere else if you want them to be ignored when using a site-local Drush.~~
  5. We'll need to make sure that we load the Drush commandfiles from the site-local locations BEFORE we look at the shared locations.

I think this should make everyone happy. If you want to keep using your global Drush extensions the same way you always have, because the autoloader will "usually work" like this, then you can. If you run into a situation where the autoloader does NOT work like this, then you can just add your global extension into the composer.json of your Drupal site, run composer install, and either Composer will grab the right version for you, or you'll get a useful set of error messages about the specific version incompatibilities that you are experiencing. Should be just a little more code, and we'll be done. I think I can wrap it up early next week.

@greg-1-anderson greg-1-anderson added this to the Drush7 milestone Jan 31, 2015
@greg-1-anderson
Copy link
Member

I realized that (4) and (5) are a mistake. Rather than adding magic behavior to --local, we can just have folks add additional commandfile include locations in their site-local drushrc.php files. This does not work today, because Drush only checks for commandfile / config includes once, and it is too late to modify these by the time the site-local config is sourced. We could change this behavior, though; all we would need to do is remember which locations we already sourced, and test to see if any more were added every time we source another config file.

@greg-1-anderson
Copy link
Member

Interesting side note. If you use the composer packagist repository http://drupal-packagist.webflo.io/, it automatically inserts dependencies from Drupal modules to Drupal core, and from Drush extensions to Drush. See:

See: drupal-composer/drupal-parse-composer#3

Their model is, if you use composer to install a Drupal module, then it is also expected that you are using composer to install Drupal core, and these are part of the same composer project. This also extends to Drush extensions and Drush--if you install your Drush extension from http://drupal-packagist.webflo.io/, the assumption is that you are using a site-local Drush.

Other packagist repositories do not have this assumption, but I thought it was interesting to mention this here.

greg-1-anderson added a commit to greg-1-anderson/drush that referenced this issue Feb 6, 2015
…ser libraries can interact with Drush via Drush\Drush::autoload().
greg-1-anderson added a commit to greg-1-anderson/drush that referenced this issue Feb 25, 2015
…ser libraries can interact with Drush via Drush\Drush::autoload().
@greg-1-anderson
Copy link
Member

More discussion on local-vs-global commandfile management in #1340.

@greg-1-anderson
Copy link
Member

I recently had to resolve a difficult problem I was having with site-local Drush and Drupal 8. When I used the d8 site with the global Drush, it worked fine, but the site-local Drush was crashing in the terminate() method.

It turned out that the problem was a vendor directory that I had created in my ~/.drush folder via cd ~/.drush && composer require org/drushextension. The result of doing this was that my ~/.drush/vendor directory had a copy of Symfony in it, and the version of Symfony in ~/.drush/vendor was older than the one currently in Drupal 8. One of the Drush extensions inside of ~/.drush/vendor was including the autoloader from here, which caused a conflict with the identical classes in Drupal 8, leading to mysterious and spectacular failures that were pretty hard to track down.

After this experience (which other people have also experienced), I now firmly and strongly believe that Drush extensions, Drupal modules, and any other manner of plugin should never include any autoload.php file. Only top-level components (the front controller, Drupal, Drush, Behat, etc.) should include the autoloader. Plugins should always live in the same autoloader as the app they plug in to.

So, how should a Drush extension insure that its autoloader is included? The current answer is to call the function drush_autoload(__FILE__) from the init function in your Drush extension's commandfile. This will go ahead and do the deprecated thing, and include your local autoloader if it is necessary; if it is not, the function does nothing. This allows Drush extensions to work in legacy environments, where the user has installed their extensions in a global vendor directory, and still also work in a site-local Drush environment. The current implementation of drush_autoload() is not quite right yet, but the point is that calling this function puts Drush in control, so changes to the autoload strategy can happen in one place, when needed.

I am working on strategies for managing Drush extensions from Composer in #1347, but this effort is still in progress.

@xendk
Copy link
Contributor Author

xendk commented Apr 22, 2015

I've been pondering this lately. I've done a few global Drush commands, and lately a few Symfony Console based ones.

I've actually considered re-doing a few of my global Drush commands as stand-alone Symfony Console commands, as their reliance on Drush could be handled as calling Drush as an external command (Symfony Process FTW).

There's something to be said about installing Drush in the site code (as anyone that's tried drush sql-sync from a local, global, Drush 7 to a remote Drush 6 will know).

My viewpoint might be skewed, but from where I'm looking, global Drush commands is increasingly looking like a wart (a historically useful one, but none the less). I don't know what others have been using global Drush commands for, but in my own experience it's mostly been for commands that could just as well been standalone shell commands that called Drush for some "low-level" Drupal work.

Back when Drush was still young, creating a command line PHP script was pretty involved, and Drush commands was a welcome shortcut. But with Symfony and Composer, it's become much easier.

I suspect that if you take the total sum of Drush commands, subtract those in modules, and those which is global due to the convenience of not installing it into every site, you'll end up with a small set of global commands that could just as well be done as standalone shell commands.

So I'll back up and suggest letting Drush do what it's named for, being a Drupal shell, not being a Drupal shell sometimes being a generic command runner. Drop global commands, and only have a global configuration file for configuration items that make global sense (overriding the ssh command line and that kind of stuff).

It'll simplify the code, and some of Drush internals might be rolled out into separate packages that other commands might use (parsing alias files and ssh'ing to aliases to run command is a few I could find a use for). Someone might even create a composer template for shell commands relating to Drupal that'll include a lib for easy running of Drush in backend mode.

It might seem a bit like a step backwards, but I think it'll focus Drush more on it's core value, and I don't think the loss of the global context is that great in the long run.

@greg-1-anderson
Copy link
Member

I think that it's a good idea to factor some useful libraries out of Drush, for use in other stand-alone cli applications.

@greg-1-anderson
Copy link
Member

I made an attempt at making Drush detect and report "dependency hell" situations in #1520. Moshe and I just discussed this, and the end conclusion we reached was that this is a hard problem, and Composer was not really designed to solve it.

Moving forward, it looks like we are going to completely disable support for any sort of global Drush commandfile in Drush 8, maybe with some way to opt-in for this behavior, maybe not.

This will formalize the recommendation above as actual Drush policy. Global commandfiles should not be Drush commands, but should instead be written with the Symfony Console component, or something similar, and 'exec' Drush when needed to operate on a Drupal site.

@ergonlogic
Copy link
Member

So... this issue started off as a request to be able to 'drush dl' extensions directly from github. Now it appears to be deprecating global commandfiles entirely. Is this just limited to installation via Composer, as #1520 suggests?

Maybe I'm mis-reading this issue (and #1513 (comment)), but wouldn't that make commands like drush make and drush runserver impossible to implement as non-core extensions? This seems to apply to 30+ other commands in core, if 'bootstrap' => DRUSH_BOOTSTRAP_NONE, is anything to go by.

FWIW, I'm fine with limiting automatic search paths, so long as this is still valid in ~/.drush/drushrc.php:

$options['include'] = array (
  'example' => '/my/command/that/does/not/need/to/bootstrap/a/drupal/site/',
....

@greg-1-anderson
Copy link
Member

We don't have a firm implementation in mind yet, although allowing opt-in of global locations, e.g. via $options['include'] in a drushrc.php, will likely be allowed. I wouldn't be surprised if this facility were also eventually removed, though (e.g. perhaps in Drush 9), if a better solution to these problems are not found by then.

You are correct that the general idea would be to deprecate the concept of providing commands such as drush make (which do not bootstrap a Drupal site) as non-core extensions. However, the definition of "global command" is "not bundled with Drush Core" and "Not installed with a Drupal site". (Aside: a command could be DRUSH_BOOTSTRAP_NONE, but still call DRUSH_BOOTSTRAP_MAX later, so simply looking at the bootstrap level is not necessarily a good metric for whether a command operates without a Drupal site or not. Commands that users typically have installed as global commands, but which are used with a Drupal site, can be installed locally with each Drupal site.

The theory is:

  1. Most Drush users are content using only the core commands provided by Drush.
  2. Of those that use more than just Drush core, most of those only use Drush commands that are bundled with a module (devel, features, etc.)
  3. This leaves us with only a fraction of users who need global commands, which Composer makes very hard to support in a way that does not lead to "dependency hell" when multiple copies of the same library, but with different incompatible versions are loaded by the autoloader.

Note that the Drupal Console project gets around this problem in a different way: it requires that your version of the Drupal Console must match exactly with the version of Drupal that you are running it with. If you have different versions of Drupal on the same system, then you'll need to install different versions of the Drupal Console in order to use them successfully with your different sites. Drush needs to work with multiple versions of Drupal, so this is not an option for us.

If a command never needs to bootstrap or target a Drupal site, it is again our theory that such commands do not need to be Drush commands; they could be Symfony console commands. Drush make could be a Symfony console command, but it is in Drush core, so it does not need to be ported.

@weitzman
Copy link
Member

weitzman commented Aug 4, 2015

This issue has been about several interrelated issues. I think we need to close it and discuss elsewhere.

  1. Dependency hell and global commandfiles - Prevent dependency hell when users try to use multiple autoloaders #1520
  2. packages.drush.org is a directory of Drush commands installable via Composer (thx @xendk)

@weitzman weitzman closed this as completed Aug 4, 2015
@greg-1-anderson
Copy link
Member

See also #2103.

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

No branches or pull requests

8 participants