I spent some time this afternoon working on making drush_shutdown() more intelligent, and realized that to do it properly we really needed to complete Adrian's vision of commands being tied to Drupal bootstrap levels (in the same way they are tied to Drupal core and module dependencies). Apart from making things more flexible, but allowing things to be run in more limited environments this also allows us to properly list commands that are available to you in your current environment.
A summary of the changes in this patch:
* Instead of lots of back and forth guessing game type logic to figure out what commands are available, we simply try and bootstrap Drupal to the maximum bootstrap level possible.
* Once we know what bootstrap level we are at, it is much simpler to filter the list to show what commands are available.
* We avoid the exits in the core bootstrap code by using a shutdown function - this is now in the normal bootstrap execution path, rather than coming just at the end of the request. This has the advantage that we can recover from pretty much anything (even module syntax errors) and still produce a usable tool. We use a similar output buffering technique to avoid the maintenance page (hopefully we can patch the Drupal 7 bootstrap to not die or forcefully redirect and to provide useful success/failure output, so we can simplify this in the future).
* The previous errors when you don't have a full bootstrap are now more just hints on how to enable more commands (and now appear at the top). I think generally having things degrade gracefully in this way (rather than lock you out completely until you get all 12 axis of potential errors configured just right) is the way to go to keep the user experience good for new users.
I am also attaching a patch to Drush extras on 6.x that adds bootstrap parameters to many of the commands. The $bootstrap_level global should dovetail nicely into Adrian's context API.
I have tested this a fair bunch, but I would appreciate it if someone could give it a run though, especially checking some of the more subtle error conditions. You can hack the if (is_null($bootstrap)) {... $bootstrap = DRUPAL_BOOTSTRAP_FULL; ...} line to force arbitrary bootstrap levels, as well as breaking your database uri in settings.php (forces level 1) or your Drupal site code (forces level 2).
Comment | File | Size | Author |
---|---|---|---|
#24 | drush_boot_env.patch | 435 bytes | anarcat |
#22 | drush_bootstrap_levels.diff | 56.02 KB | adrian |
#20 | drush_bootstrap_levels.diff | 51.02 KB | adrian |
#19 | drush_bootstrap_levels.diff | 49.63 KB | adrian |
#11 | bootstrap-command.patch | 2.76 KB | Owen Barton |
Comments
Comment #1
moshe weitzman CreditAttribution: moshe weitzman commentedI'd love Adrian's patch review on this. he is the one who thought that some commands need control the bootstrap level (presumably installer and updater)
Comment #2
adrian CreditAttribution: adrian commentedI'll review this on the plane tomorrow, but i need to review it in context of the .. err context patch.
Which needs to go in first ?
Personally, in my commands, i need to be able to delay bootstrapping, till the configurations are created correctly.
This involves moving the DRUSH_URI definition and drush_set_environment code (which correctly sets the headers), to a later point in execution (if bootstrap is not set).
ie: when you do 'drush.php install somesite.com --root=/some/drupal/path' , it needs to not bootstrap, until after i create the drupal config and the mysql database, and then bootstrap the additional levels.
Comment #3
Owen Barton CreditAttribution: Owen Barton commentedI don't think it matters hugely - there is not a very large intersection - this touches some of the lines the context patch changes, but it mostly just moves them around rather than actually changing them. This patch changes "what we do" (rather than "how we do it" as with the context patch) so from that point of view it might be worth putting in first, so we get the disruption out of the way.
Yes, and you can still do this in at least 3 ways:
1: You can set your command to run at bootstrap level -1 and it will not attempt any bootstrap (probably your best bet in your case).
2: If there is no specified/detected Drupal root then it will also not attempt bootstrap (doesn't apply in your case, since you want this).
3: You can set a bootstrap level and allow it to attempt (and fail), which will leave you at a -1 bootstrap level. This could be useful in some cases if you think there may be a site there, but you need to confirm it's status (e.g. to fix it).
Either way, once you are in you command callback, you can check the $bootstrap_level and if it is -1 you can do your installation stuff, then re-call drush_drupal_bootstrap. This will attempt the bootstrap again and then deposit execution back at the start of your command callback (or another command callback if you switched the command, which should be possible with the context patch). You can then check the bootstrap level again to see if it worked and if so, complete any post installation tasks. If you use the same command you should probably implement a $first_run static or something, so it doesn't get stuck in an infinite installation loop if it all borks and returns -1 on the second bootstrap attempt too.
Comment #4
moshe weitzman CreditAttribution: moshe weitzman commentedSounds like Install/Update needs are met, so feel free to proceed with commit of this and with the error context patch. I didn't get to test it but I'm sure we can iron out problems afterwards.
Comment #5
Owen Barton CreditAttribution: Owen Barton commentedI had a play with this and it seems to be doing something very odd to the system_module forms in the new enable/disable command (it appears that the form already reflects the changes we are about to make, before we even started applying the...very odd).
Anyway, for the time being I committed a very minimal patch to remove the dummy errors while we figure out what is going on here.
Comment #6
Owen Barton CreditAttribution: Owen Barton commentedI am going to take a shot at getting this and #385898 playing nicely together on the plane tomorrow.
Comment #7
Owen Barton CreditAttribution: Owen Barton commentedFigured out the wierd issue above (we needed to do an "exit" rather than call the drush_bootstrap_continue function directly, so that the function is removed from the shutdown callback list). Committed the patch to HEAD.
A good followup patch would be to add some help to let you know if/why some commands are not listed, and provide a simple way to let you list all of them (rather then just the runnable ones) - probably just an explicit "drush help".
Comment #8
anarcat CreditAttribution: anarcat commentedI should note that this commit breaks provision, I don't exactly understand why. From what I understand, now drush bootstraps as much as it can now, which will break provision since it sometimes needs to do some things (like creating the settings.php) *before* bootstrapping. In short it needs much better control over the bootstrap workflow than what's available here.
In fact, I think there's been a conceptual confusion about the 'bootstrap' flag in drush command declarations. This patch assumes it's "minimal bootstrap level necessary to run the command" whereas I think it should mean "do not bootstrap beyond that level". Maybe we need both?
Not sure where to go from here now. I'll test my luck at putting this back to 'needs work' since this was done for provision after all...
Comment #9
Owen Barton CreditAttribution: Owen Barton commented@anarcat - this was indeed the original intention, but seemed to have got lost along the way - it should be easy enough to add though - I am happy to have a shot this weekend if you don't get to it first (just after $bootstrap_level = -1; in drush_bootstrap make a call to fetch all commands and pull the bootstrap level out of one, if provided).
An alternative approach is to let it fail to bootstrap, do your settings.php stuff and then recall drush_drupal_bootstrap() with your next bootstrap level. In some ways this is more flexible, because you can check that the site is not already existing and functional and so on. We do something like this in drush dl, with an "optional" conf_path level bootstrap to allow more magic in the download location logic.
Comment #10
Owen Barton CreditAttribution: Owen Barton commentedHere is a quick sketch of what I am suggesting. I am not sure $check_bootstrap is the best level of abstraction (perhaps command list altering should be a hook?) but it's a start.
Todos (not necessarily all in this issue):
* Provide a help function to list all commands (rather than just the "available" commands).
* Port the patch to add bootstrap levels to drush_extras.
* Fix up the drush_set_error(DRUSH_DRUPAL_DB_ERROR); help to display in more appropriate places.
* Perhaps provide some generic constants and help somewhere of at least the most useful bootstrap levels.
Comment #11
Owen Barton CreditAttribution: Owen Barton commentedOh...and the patch...
Comment #12
adrian CreditAttribution: adrian commentedThis was committed, and broke all the provision commands. http://drupal.org/cvs?commit=182490
We need the bootstrap to set the maximum level to boot to, and not the minimum required level to boot to.
http://drupal.org/node/400034
I also think it's wrong that all the application logic is in the shutdown code AND the documentation is also incorrect.
I am reverting this patch , and will look at it more closely on monday. http://drupal.org/cvs?commit=182904
Comment #13
Macronomicus CreditAttribution: Macronomicus commentedI had to go back to 1.44 in order to fix this on my build.
1.48 killed my queue dispatcher --- 1.47 or #387214 killed my provision
Everythings happy again @ 1.44
^_^
Comment #14
moshe weitzman CreditAttribution: moshe weitzman commentedWould be great if Owen and Adrian could get this sorted quickly. We really need to release Drush 2 ASAP. Our current situation is confusing for many potential drush users. I removed all releases from the project page except HEAD because I have no intention of supporting them.
Comment #15
adrian CreditAttribution: adrian commentedNow that context is in, I'm busy working on a new version of this patch.
It's essentially modeled after how Drupal does it's bootstrapping, with the addition of some drush specific levels.
This will allow any command to specify the level to bootstrap to, and allow the help command to sequentially boot to new levels.
This will also allow us to cleanly tie the error handling into the current bootstrap level, and reliably detect more errors (such as not having a proper drupal root, not having a proper site directory, the 'site not found' error)
I'm still trying to determine what the default bootstrap level is going to be.
Comment #16
adrian CreditAttribution: adrian commentedSo here's a weird little issue that I see cropping up.
So essentially when dispatching the command, it will start at bootstrap level 0, find the relevant commandfiles, boot to bootstrap level 1, do an additive find, etc.
However, when it finds a command with a lower bootstrap level, let's say for example 'status' (this is not an actual case, just a pertinent example), it should cease trying to find a command with a higher bootstrap level, and dispatch the command.
However, if you then add a command called 'status modules', which requires a higher bootstrap level than the 'status' command which is found and evaluated first, it will never reach that command.
I can't think of a way around this, and I think it's actually the way it's supposed to work. So it should be documented at least.
Comment #17
moshe weitzman CreditAttribution: moshe weitzman commentedMy first inclination is that we can just document this somewhere and accept the limitation.
Comment #18
adrian CreditAttribution: adrian commentedI've been doing some more work on this patch, and i've found a pretty solid approach.
What i've been doing is taking the drush_bootstrap as it is now, and moving the code into their own functions.
This means the code that is used in drush_bootstrap to set the constants is now callable up to a specific level.
The levels are :
Any command that needs to bootstrap to a lower phase than full, will be able to further bootstrap at it's own convenience using drush_bootstrap(DRUSH_BOOTSTRAP_WHATEVER).
When drush is initialized now, it will sequentially try to bootstrap to the drupal_full level, and test whether there is a command that
should be executed at the current bootstrap level, if there is it will hand over control of bootstrapping to the command using drush_dispatch.
Comment #19
adrian CreditAttribution: adrian commentedHere's the patch.
I tested this with hosting/ provision (where it's mostly working .. but i think the issues that remain are on my side), and on drush_extras 5.x (which i didn't modify at all).
I added another bootstrap level to require a valid login to the site.
Comment #20
adrian CreditAttribution: adrian commentedhere's a new version of the patch, with more logging (only visible with --verbose)
Comment #21
moshe weitzman CreditAttribution: moshe weitzman commentedI reviewed this, and am comfortable with committing this once the dl command is working properly. Nice work, Adrian.
Comment #22
adrian CreditAttribution: adrian commentedHere's my latest version of the patch, fully tested with hosting and provision (the companion patches are here : http://drupal.org/node/411822)
I'd like to get this committed ASAP, so i can have a solid base to make smaller patches on. I'm maintaining over 100k's worth of patches across 3 projects for this stuff.
Any further issues we find we can create new, simpler issues for.
Comment #23
moshe weitzman CreditAttribution: moshe weitzman commentedI fixed up dl command and committed this. Thanks Adrian.
Comment #24
anarcat CreditAttribution: anarcat commentedA typo went in at some point, here's a trivial fix.
Comment #25
anarcat CreditAttribution: anarcat commentedSorry, wrong issue.