Problem/Motivation
Drupal's bootstrap is independent of the Kernel, meaning our path towards Kernel based testing is rocky.
Proposed resolution
Make the kernel bootstrap Drupal and itself by adding a static kernel factory method to Drupal\Core\DrupalKernel thus DrupalKernel::createFromRequest(Request $request);Refactor index.php/installer/etc to use this instead of bootstrap phases. We will need to provide backwards compatibility for drush so drush si and drush en aren't broken (used by testbot).
Remaining tasks
None
User interface changes
None
API changes
conf_path() gets deprecated in favour of DrupalKernel::getSitePath() or DrupalKernel::findSitePath()
Super globals are removed from the bootstrap process and drupal_bootstrap() becomes deprecated. Instead DrupalKernel::createFromRequest($request) can be called to retrieve a kernel then the boot method called in intialize the container and other systems. Alternatively, a kernel can be directly instantiated and the boot() method called. If manually creating a kernel, Settings must be manually initialized.
Original report by @username
We currently do quite a bit of work before we can instantiate DrupalKernel. Because of this, early configuration and servies that would normally go on the service container are configured by global variables. We also have code in this early bootstrap that requires access to the request (conf_path, drupal_environment_initialize, request_uri, drupal_valid_test_ua, etc), but we don't have the request until DrupalKernel::handle() is called, which is too late, so we're still accessing global $_SERVER. I hope we can all agree that needing access to global request variables defeats the purpose of using Symfony's HttpKernel. These are fixable problems for a running Drupal site. We can move things like conf_path to kernel wrappers (middleware) that get the request and set environment variables that DrupalKernel can pick up (a bit cleaner than globals). One problem with this approach is our installer. It requires variables like $databases and $config_directories to be mutable globals. Since we have a different front controller for the installer (install.php), this is fixable, just a PITA. The real problem comes with simpletest. It fires off a batch api request, which runs through the main front controller. Drupal is loaded like it was a normal request, then WebTestBase::setUp changes a bunch of global variables around and calls the installer functions directly. This carefully orchestrated global mutation makes it impossible to encapsulate our bootstrap configuration. I worked on this for several days, using a number of different approaches, and each failed in new and unexpected ways because of simpletest and the installer. We also don't have unit tests for what would break here, making the process of refactoring prohibitively difficult. I very much wanted to start this issue with a patch, but I've got nothing. I tried to trim down what I was working on to something simple that was at least a step forward, but the best I can do is just move our existing code around. I don't see a way forward while WebTestBase exists, but I'm hoping someone else sees something I don't. If this cannot be fixed in D8, we might want to consider rethinking how we use DrupalKernel so that it isn't an awkward mix of our old bootstrap and what a Symfony app normally looks like.
| Comment | File | Size | Author |
|---|---|---|---|
| #249 | kernel-bootstrap-factory-2016629-247.patch | 510 bytes | neclimdul |
| #236 | kernel-bootstrap-factory-2016629-236.interdiff.txt | 13.46 KB | neclimdul |
| #236 | kernel-bootstrap-factory-2016629-236.patch | 142.48 KB | neclimdul |
| #205 | kernel-2016629-neclimdul-factory.interdiff.txt | 7.2 KB | neclimdul |
| #203 | bootstrap_patch.png | 29.89 KB | msonnabaum |
Comments
Comment #1
sdboyer commentedthanks for this...
it'd still be helpful to have your unsuccessful approaches up somewhere, for our own digestion purposes.
from my brief look over of
TestBaseandWebTestBase, it seems rather like what we need to do is bite the bullet, rewrite the installer encapsulated within anInstallerKernel, then rewrite those methods to interact with the installation through that kernel by mucking with a request object.yikes.
Comment #2
msonnabaum commentedTo help illustrate the issue here a bit better, I threw together this patch. It's very ugly and naive, but it should clarify what's wrong.
The main idea here is to not require any setup before we instantiate DrupalKernel, so I just moved it all inside the handle method. I moved it there instead of boot, because the methods that get called before we call parent::handle need the Request (I didn't change them to use it in this patch however).
I also had to move the container building into handle(), because we need to have already loaded settings.php to instantiate the BootstrapConfigFactory (there may be more dependencies past that, I just stopped there).
As bad as it looks to call boot() within handle(), after we've already done quite a bit of work, it's a more honest representation of our situation. The way we use boot() is more or less an additional bootstrap step.
All that said, this patch should actually work on an existing d8 install. This could be refactored into something more manageable, and would be a step forward from what we have now. However, if you want to see where this starts to break down, try the installer.
Comment #3
lsmith77 commentedSo my question given the current challenges I wonder if its impossible to at least make a patch available for advanced developers that do not need a web installer but who do need to integrate with other HttpKernelInterface applications and want to leverage stuff like stackphp.com? A semi official patch to make that happen might go a long way ..
Comment #4
webchickx
Comment #5
andypostinstaller left for 9.x #1530756: [meta] Use a proper kernel for the installer but there's sandbox https://drupal.org/sandbox/Letharion/1615168
Comment #6
andypostinstaller left for 9.x #1530756: [meta] Use a proper kernel for the installer but there's sandbox https://drupal.org/sandbox/Letharion/1615168
Comment #7
larowlanWhat about using .htaccess to provide a second front-controller for simpletest.
And a second installer.
Then something like so
And for the installer
Then we can break this circular dependency
Comment #8
Crell commentedHow would that work for non-Apache web servers? We have an IIS config file we could probably modify the same way; I don't know about nginx.
Comment #9
moshe weitzman commentednginx config is pretty well documented. it has easy equivalents apache/iis routing. this is a pretty intriguing proposal IMO.
Comment #10
larowlanin which case I might kick the tyres on this
Comment #11
larowlanOk re-roll and refactor.
Let's iterate from here.
a) Manual install works.
b) run-tests.sh seems to work (tested a few tests and they passed).
c) Simpletest UI seems to work (tested a few tests and they passed too).
There is plenty to do and this doesn't remotely look like polished code.
From here I think we can continue this pattern.
Most of the drupal_bootstrap(SOMETHING)
become DrupalKernel::bootstrapSomething.
bootstrapSomething knows it needs to call bootstrapSomethingBeforeIt.
Once we get to bootstrapCode we need a kernel instance because we need to boot a container.
So we create, boot and return static::singleton from bootstrapCode.
I think from here we can start chopping out chunks from drupal_bootstrap and then start looking at using other statics/properties on DrupalKernel instead of the globals that simpletest has to mutate.
Lets see how borked this is from the bot's point of view, as I said - I ran some webtests locally and they passed without leaking into the main site, we're only moving stuff about so no reason why it should leak.
Drush doesn't work with this patch.
And in some places I'm getting Symfony\Component\DependencyInjection\Exception\InactiveScopeException: You cannot create a service ("finish_response_subscriber") of an inactive scope ("request"). in service_container_->getFinishResponseSubscriberService() but I think that's down to a botched re-roll because the original patch pre-dates the changes to request scope... but I can't see them in the diff.
Comment #13
larowlanwhen did testbot switch to using drush si?
what are the options here?
this breaks drush...
Comment #14
andypostComment #15
damien tournoud commentedI suggested a different approach a long while back: https://drupal.org/comment/6757918#comment-6757918
I would like to see something like this:
Comment #16
moshe weitzman commented@larowlan - I also didn't know that bot used drush site-install. I thought we used this pift code. That indeed is problematic for installer patches like this. I was about to suggest working on #2115533: Add InstallerInterface to provide a stable non-interactive installer but I see you are already there. Nice!
I will add that if that issue gets stuck, there was a simpler proposal for pift to use its own small Drush command which would be much simpler that site-install, and would be maintained in core (and thus could move along with patches that change the installer). See #1317528: Separate the testbot from the installer.
If we end up needing help on the Drush side, I'm happy to pitch in.
Comment #17
Anonymous (not verified) commentedFWIW, i agree with #15.
Comment #18
larowlanThat makes three of us.
Comment #19
msonnabaum commented#15 makes it more explicit, which I think is positive.
The alternative is just calling boot() (or whatever ours would be called since it's pretty different than symfony's) in our implementation of handle(), passing it the request.
Having a kernel factory that sets up the basic information for which site to use seems pretty sane to me.
Comment #20
larowlanmore changes
Comment #22
larowlanNew personal best!
Comment #23
larowlanmore whittling
Comment #25
larowlan23: kernelify-bootstrap-2016629.23.patch queued for re-testing.
Comment #27
dawehnerIt would be great if someone could write a proper issue summary.
Comment #28
larowlanbah, language negotiation relies on variable system, so still need to boot that (another reason to go and review the language negotiation patch)
so changes made:
- adds a request subscriber for the theme negotiator - still calls out to the drupal_theme_initialize function but removes the call to setRequest on the theme.negotiator service, meaning we can drop drupal_bootstrap_full(). That stuff needs a good cleanup, lots of deprecated code including calls to drupal_add_js etc. Note this adds a $request parameter to it so we can call it from the request subscriber.
- boots the variable system after db and cache is available.
- fixes some uses of $_SERVER instead of the request in dblog
Hoping this will have less fails so then I can start the real cleanup work.
Also some of the code in here should be spun off into separate issues - eg it makes sense for conf_path() to take a $request parameter instead of using the super globals, same with the theme negotiator request subscriber.
Comment #30
larowlanmeh drush en simpletest fails :(
Comment #31
larowlanstick back some BC stuff so drush keeps working
Comment #33
larowlanyeah, updated arg order of conf_path() to support drush but didn't revert changes made elsewhere
Comment #34
larowlanUpdated issue summary
Comment #36
larowlanre-roll after language patch, lets see how we go now, still expecting theme fails
Comment #38
larowlan45 minute test run, must be my lucky day
fixes statistics fails, who knew we had a statistics.php, not I said the wolf
Comment #40
larowlandoh, forgot that priority works opposite to weight, so my theme init service was firing after PathSubscriber and admin theme wasn't being set because _system_path wasn't available on the request.
so this fixes admin theme, which should fix a lot of tests that look for specific markup (I'm looking at you HelpTest).
Also fixes warnings from dblog.
Fingers crossed for 1733 again, 45 mins is nice
Comment #42
larowlanFixes http.php and https.php didn't know we had those either.
Logic there is funky at the moment but hoping in the final iteration we kill the testOnly concept, also hoping #2171683: Remove all Simpletest overrides and rely on native multi-site functionality instead helps here too.
Fixes any test with locale enabled - here's the problem:
* when locale isn't enabled calls to t() inside various hook_stream_wrappers() don't do much
* when locale is enabled the call to module_invoke_all('stream_wrappers') calls t() in various (system_stream_wrappers, locale_stream_wrappers et al)
* this calls into LocaleLookup which then in turn requires the current_user service
* which requires the synthetic request service
so I'm entering the request scope (which we have available thanks to DrupalKernel::createFromRequest) and it stops blowing up.
But it is pants, the request scope shouldn't be entered until we call DrupalKernel::handle(), at least thats what I reckon.
So hoping that #2028109: Convert hook_stream_wrappers() to tagged services. will help here too.
Is there a reason to call t() on name/description of file wrappers, they're such a low-level concept.
Anyway, lets see what bots says.
Comment #45
larowlanreroll after update.php was gutted.
Comment #47
larowlanvariable_initialize() is dead
Comment #49
larowlan47: kernelify-bootstrap-2016629.47.patch queued for re-testing.
Comment #51
larowlanRe-roll after #2171683: Remove all Simpletest overrides and rely on native multi-site functionality instead, go bot go
Comment #53
larowlanMissed some whilst rerolling, this fixes one of the failing tests locally, given the number of fails expect it will fix a lot of them
Comment #55
jibranIt'll fix
Undefined variable: pathinDrupalKernel.php.Comment #57
jibranI hate
CollapsedDrupal\file\Tests\UsageTesttest :@Comment #58
jibran55: kernelify-bootstrap-2016629.55.patch queued for re-testing.
Comment #60
larowlanslowly slowly down they came
each dog part of a long dog chain
Comment #62
moshe weitzman commentedWhat's the current state of this dog chain? :). Any blockers we should be working on?
Comment #63
larowlanJust need to find time..
Comment #64
larowlanre-roll
Comment #67
larowlanconfig.inc is gone
Comment #69
larowlananother re-roll
Comment #71
larowlanMore fixes
Comment #73
larowlanneeded another re-roll, velocity++
Comment #75
larowlanFixed reference to drush as legacy. It isn't, just the function.
Comment #77
ianthomas_ukDeprecation messages should be specific about when the function is planned for removal, e.g.
@deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0. Use \Drupal\Core\DrupalKernel::confPath().
Comment #78
larowlanre-roll
Comment #80
larowlanI have simpletest test passing and know what the issue is with the theme and menu tests. But after five hours, I can't get the session https test to pass, although I've got closer than the last patch.
Can someone following this point we to where Drupal sets the cookie with the session name as manual testing suggests this cookie isn't getting set on login from the mock https bits of the test. I've stepped through both the mock login and a normal login and they seem identical yet for the mock https login the session cookie is never set. Also can someone confirm that https cookies even work in head as this test might be iffy too, and the changes are picking that up, I'm at a loss.
Comment #81
moshe weitzman commentedI searched for 'setcookie' and found a few instances that look like what you are wanting. See https://github.com/drupal/drupal/blob/f01c994de8d6f54a5bef1523319c6da880...
In my travels I also saw a warning against setting cookies on 'localhost domain name. See http://us2.php.net/manual/en/function.setcookie.php#73107.
I have never used https cookie so I can't easily help there.
Comment #82
damien tournoud commented@larowlan: if you look at the test log, the call to https.php still returns a status code of 500, which suggest that an exception was raised in the mock path, at least on the test bot. Do you know which exception that is?
Comment #83
larowlanThanks Moshe and Damien
I had grepped for set cookie and had breakpoints on all instances in core. The code you've linked to is no longer in Drupal 8. I'm wondering if perhaps we're using symfony code to set the session cookie but I had breakpoints on those calls too.
Damien, I have another version locally where I changed the order of creating the request, like you suggested on irc, in not getting the 500 anymore. I'll upload that later today.
Thanks again
Comment #84
larowlanhere's where I'm at, I think this should be sub-20 fails (famous last words)
Comment #86
larowlanwhoops, had some stuff I'd taken out when working on the menu router/theme fails
Comment #88
larowlan#1316692: Convert hook_admin_paths() into declarative properties on routes is why the fails are up, need to investigate.
Comment #89
larowlanOk, this should be enough to move back in the right direction after #1316692: Convert hook_admin_paths() into declarative properties on routes
Comment #91
larowlanAnd then there were 6.
5 fails in session https test, which I've tried in vain and at length to fix, any help appreciated.
1 in menu router test which I'll look at tonight after work.
Mental note, need to clean up the statics in the terminate() method so subsequent calls to ::createFromRequest get a clean kernel.
Comment #92
larowlanand the magic number is 29 - the theme init subscriber needs to run after routing (32) and after maint subscriber (30)
Comment #93
larowlanComment #94
msonnabaum commentedThat feels like a sign that these should not be event subscribers. It'd be a lot clearer if we just invoked them by hand in the order needed.
Comment #96
larowlanwrong patch
Comment #98
ParisLiakos commentedthis works (at least locally)
also cleanup some outdated code
Comment #99
pounardSatan!
Comment #100
moshe weitzman commentedI think that PHP is sending the cookie on its own, without any setcookie() call in Drupal. While trying to debug his, I put a breakpoint in curlHeaderCallback() and notice that we are in fact receiving a secure cookie back from Drupal but its name does not match $secure_session_name so the assertion fails. It seems odd to me that we call session_name() in the test (i.e. parent site) and expect that session name to be same on child site.
This test looks pretty brittle to me. It tries to emulate https without the webserver supporting https. This is a big enough hack that I'm not sure the test is really worth keeping?
Comment #101
larowlanMoshe: that was my conclusion too, but Paris managed to make it pass so now the real work can begin.
Comment #102
dawehnerImpressive work. This is just a drive by review
Is there a reason why we can't just force to pass in the request?
Small note: we could just use @return static
small typo here.
Is this really a situation when we want to trigger a watchdog call? This seems to be for me an exception
This is defined in the HttpkernelInterface so you could just get rid of this bit.
Another small typo.
You can easily get rid of this by using a synchronized request or even better a request stack. I guess the second one would be out of scope of this patch.
In general though the important bit of this subscriber is the theme initialization.
We need more @file statements :P
f
Comment #103
larowlanstarts the real work, removes all calls to drupal_bootstrap().
so only drush left calling it (testbot).
doesn't address #102
ignores the settings() in interdiff, since fixed
hoping still green
Comment #105
larowlanadding beta target, cause planning to remove drupal_bootstrap().
fixed run-tests.sh
Comment #107
larowlantoo aggressive on cleanup
Comment #109
larowlango again, also think there's some fails in head, node translation ui or some such?
Comment #111
larowlan109: kernelify-bootstrap-2016629.109.patch queued for re-testing.
Comment #112
larowlanoom errors, hoping testbot
Comment #114
larowlanand again
Comment #116
larowlanInterdiff against 98.
Also fixes items in #102 except for #102.1 which is a much bigger issue and should be part of a larger theme system cleanup once this is in, in my opinion.
I spent an hour or so trying to make every usage of drupal_theme_initialize() pass in the request, its just a spaghetti mess, sometimes its even called when the request stack has no request object. So putting in the follow-up/out of scope basket.
Retains the terminate cleanup but doesn't address existing calls to drupal_bootstrap like patches 103->114 tried to do unsuccessfully. Going to do those in smaller steps to keep it green, tried for too much in one pass.
Also removes LegacyRequestSubscriber cause I don't see a need for it anymore
Comment #118
larowlanfixes cache and adds public bootPageCache method to replace _drupal_bootstrap_page_cache.
At the time this is called we have a booted kernel so we can continue to refactor that code to use the actual container ($this->container) instead of the globals/\Drupal object, but thats next pass.
Comment #120
larowlanshuffles stuff around to suit update.php
Comment #121
larowlanGreen again
Ready for serious reviews now
Comment #122
ParisLiakos commentedshouldnt we remove the require_once too?
kernel will take care loading it
unneeded too?
this should be removed
Comment #123
jibranok
Finishes
Attempts
Can we try using it?
Is it still pending or this is for follow up?
Comment #124
larowlanneeds @todo remove once https://drupal.org/node/2028109 is in
Comment #125
sunSince this is a very important patch, I started to help @larowlan to get it done behind the scenes. We're collaborating with concurrent branches in the Platform sandbox.
My changes of yesterday, which should address all of the nitpicks from earlier comments + many additional ones:
@larowlan and I already discussed some further changes that will make it simpler to review this patch, so stay tuned.
If time permits, I also want to try whether it is possible to generate a diff for the moved code between bootstrap.inc and DrupalKernel to further facilitate reviews.
Comment #126
sunMajor update. Simplified changelog of changes performed by @larowlan + me:
Also attaching an interdiff, but since we had to merge latest 8.x a few times due to conflicts, the interdiff is a patch-serial reflecting the commit history (sans merges).
Comment #127
jibranI know it is very basic functionality and if it is not working right then Drupal will not work but I have to ask is there a follow up issue to add unittest for DrupalKernel?
Comment #128
sunMerged 8.x + fixed merge conflicts after #2228341: Objectify session management functions + remove session.inc
Comment #129
mile23Is this scheduled to go away after everything's all injected? (Please say yes.)
It makes a bunch of the kernel untestable.
Comment #130
neclimdulI raised similar concerns in IRC. Crell pointed out that most of the global environment stuff could be called multiple times without problem. Someone else pointed out we could have a factory that did the environment cleaning.
There are some other things like Settings that make a singleton sort of required ATM though... If you instantiate 2 kernels with different requests built from different paths, you could replace and completely destroy the setting state of the first Kernel.
Comment #131
mile23You mean like SimpleTest will be doing? :-)
The kernel should be available in the container, for any code that needs it, because the container is already injected everywhere.
And boom:
..there it is.
Do not use a singleton for this.
Or any singletons or static anything.
Please.
It's a design discipline that will pay off in reduced DrupalWTF.
Comment #132
moshe weitzman commentedI went through the bootstrap in the debugger and I'm quite happy with this patch. Great work! A couple thoughts which can be deferred to follow-up issues if desired.
Comment #133
Crell commentedWhy does this parameter need to be optional? Is this for testing?
The first case is a no-op; the second is documented as impossible. So just reduce this to the 3rd option.
Can't we turn find_conf_path() into something less global-function-y? We're moving everything else around, why not this?
Is install_goto() small enough that we can just inline it and avoid the function call? (DRY should not be taken to the point that it forces tight coupling.)
The sentence grammar is poor here. I think you mean: "Extra slashes may appear in URLs in some circumstances. For instance, they may be added by Apache. Normalize the path to never have a leading or trailing slash.
Shouldn't we therefore pass the test-only flag in through bootKernel()?
Unsurprisingly, I am very uncomfortable with all of the static methods here. Most seem like they should just be folded into the kernel object's initialization process (either in handle() or boot() or whatever). I understand that we still have enough legacy code that it's hard to fix here, though. Is there a plan moving forward to deprecate and remove those? If so, they should be marked as such.
As Miles said, Singletons are teh evilz.
Moshe: common.inc vs. bootstrap.inc was original, AFAIK, to minimize the amount of code that needed to be parsed for a page cache hit. However, when using an opcode cache there is no code parsing so that distinction is no longer meaningful, and I'm still pushing for page caching to be handled separately anyway. (And it's already handled by a reverse proxy in high-performance cases anyway.) In practice I'd say that distinction is vestigial, and we only even have it for legacy reasons. At some point we should probably just combine those files, and/or refactor them out of existence.
Comment #134
neclimdulThanks Crell. Some good points, I'll look into them in my refactoring.
1) I think so... We like our shortcuts. I'll play with making it required.
2) So, I killed the no-op. The comment on the second case is actually wrong though, we can actually hit that code. There are lots of calls to conf_path() sprinkled around in hook_install's and such. The longer term solution would be to make it required so the caller gets explicitly clear behavior but I didn't go that far.
3) I don't see why not. I don't see any explicit calls in core so it seems like internal implementation.
4) err... um... sure? Tecnhically this is the functions documented reason for existance though and it is ugly.
5) no problem
6) sure
So on the statics(and singleton), I've done most of the refactor removing the singleton but sun raised some valid concerns so I'm re-refactoring. Not prime time ready yet but hopefully will get something together this week.
Re:common.inc vs bootstrap.inc, I actually rolled some of that out already. Not so much because of loading less code, but because really common.inc is part of the "boot code" step anyways. And with an explicit page caching step like moshe mentioned this just naturally moves back and works cleanly.
Jumping back I liked moshe's explicit page cache step and incorporated it. It let frontends not doing page caching explicitly bypass caching(win), it cleaned up some responsibilities(win) and some code and it opens up a possible API for returning a request rather then outputing and exiting(win). On miss it just returns $this. Currently it outputs and exists still but it could return a simpel HttpKernelInterface that does no routing and just returns the cached response instead of returning a response directly from the method but it would still be fairly clean.
Something like this:
Comment #135
neclimdulTo get rid of the singleton and factory entirely I had to do a few more changes then I wanted. With all the merges I had to do, I don't have a useful interdiff. sorry.
The test bot can't seem to handle this patch but I wanted to get it over here for review. The testing issue I ran it on the runner failed in weird ways installing the parent site. The latest version of Drush has no problem installing the site but testbot is pinned to a commit in December and I can't get that to even work locally. So basically, this is blocked on #2206501: Remove dependency on Drush from test reviews or updating drush in the pifr puppet repo.
Comment #136
moshe weitzman commentedUntil we get #2206501: Remove dependency on Drush from test reviews, rfay offerred to up the SHA1 on the drush checkout. I'm willing to make a 7.0.0-unstable1 tag for the benefit of folks who need to deploy drush7 now, like testbot, acquia, pantheon, etc.
Comment #137
neclimdullets see what the bot says. minor doc changes and some merges.
Comment #139
neclimdulFinally green. No interdiff because all the merge conflict resolutions from several back merges to keep this in sync made it pretty useless.
That said, its actually mostly the same patch because the code worked. I just had to do a lot of hacking of the hard coded psuedo bootstraps in simpletest to use the kernel instead. There is one change to the kernel bootstrap though to support this (I know, yuck). I moved manually settings up the container from DrupalKernel::boot() into a lazy load in DrupalKernel::getContainer(). The reasoning is a bit complicated but it boils down to boot() initializing/resetting global Settings and tests needing to change settings then reboot the kernel/container to run a different set of tests. Simpletest therefore has to change the global settings after boot and before the container is built.
Comment #140
moshe weitzman commentedStill a great patch :). I have only minor comments
+ // Immediately boot a new kernel into the regular production environment.This could be confused with a site’s prod environment. Can we disambiguate a bit?
can this move earlier in the request, like right after autoloading is available?
This bit, from run-tests.sh, is a bit surprising. I didn't look into why we need to do this manually here. Care to explain?
The indentation of the last line is two more spaces than expected. Is that deliberate?
Comment #141
neclimdulGood questions.
The installer is hard to follow but I think at this point booting to the "production" environment is sort of what is happening. That said, maybe this is more clear:
I think I just kept the location of Timer from previous patches which follows the flow of the old bootstrap. I don't see why we can't move it earlier though.
Yeah, this one is complicated. I did actually try removing it but this code can't call bootCode() because it is setup to run a kernel without a settings file and the container will run in to trouble. If I remember correctly, the problem is the lack of 'hash_salt' and calls to module_handler in bootCode() that setup the file stream wrappers.
Wasn't sure if anyone would notice that. Actually I did the indentation because handlePageCache() and handle() are being called on kernel's while the prepare() and send() get called on a response object.
Comment #142
neclimdulCleaned up the documentation in the installer. Moved Timer. Documented the response handling.
Actually, it looks like the getContainer() fix I added might let us get rid of that legacy include code in run-test. Ran some spot tests but lets see what the testbots say.
Comment #143
neclimdulerr, test bots.
Comment #144
moshe weitzman commented142: kernel-bootstrap-142.patch queued for re-testing.
Comment #146
neclimdulMerge commit is the work I did to merge #2248985: ScriptTest fails on Windows, runs against parent site #2240007: Regression: early installer is not in RTL after selecting RTL language #2176621: Remove global $databases and #2225605: Use request stack in form builder. Mostly just shifting things around but I did add request stack setup to preHandle to support the "bootstrap" changes made in #2225605: Use request stack in form builder.
There was a warning I managed to trigger that exposed that at some point we missed adding the testOnly variable to the DrupalKernel class so that's in the interdiff.
Comment #148
sunAfter plenty of discussions between @neclimdul and me in IRC over the past few weeks, in which he suggested many debatable changes, I was very hesitant to look at the refactored patch, because I feared tons of changes I'd disagree with... ;)
But turns out that this re-incarnation looks very sane now. @neclimdul successfully resolved almost all of my concerns. :-)
tl;dr: The current patch is a definitive improvement over the last incarnations of @larowlan and me. It gets rid of the singleton and cleanly resolves some other aspects. We're 95% done, only a few issues remain, ~3 major, the rest is minor (but should be addressed nevertheless). I expect this patch to be RTBC and committable in the next 1-3 days.
Hm. This looks very fragile to me. I expect
boot()to boot up a service container, regardless of what may or may not be called afterwards.Is it possible that the change to move the container initialization into
getContainer()is a stale remnant of your former refactoring attempts?I can't really see a reason for why the container initialization couldn't be moved back to the end of
boot()now.Let's rename this method to
prepareLegacyRequest()to be 100% clear.preHandle()sounds like something I'm supposed to call in a modern front-controller.prepareLegacyRequest()is something I won't bother to even look at. :-)Let's also shorten the phpDoc... it's veeery wordy/slangy. ;)
Hm. These changes seem to have been separated into/incorporated from #2246611: Document ModuleHandler pre-conditions
Let's get that patch in first.
Note: (just because this pattern disturbingly repeats itself through the entire patch)
We do not add a blank line at the top of functions and methods.
It would be good to remove all of those superfluous lines throughout the touched/added functions in this patch... Most seem to have an extraneous blank line at the beginning.
Otherwise, someone will have to clean up after you ;)
(Also happy to do that + some more comment polishing, once the latest/final changes are pushed into the sandbox.)
We're removing the minimal/mocked container from
TestBasein #2196241: Remove string translation services from TestBase container, so$this->container->get('request')will no longer be available.Let's just replace that with
Request::create('/install.php');Already mentioned + discussed in IRC:
Unfortunately, this breaks the purpose of rebuild.php /
drupal_rebuild().rebuild.php is run when it's not possible to boot a kernel (due to changed code), so the change to boot a kernel upfront and inject it into drupal_rebuild() doesn't work.
rebuild.php only boots to _CONFIG in HEAD, so as to initialize Settings. drupal_rebuild() then proceeds to kill each and everything + rebuild all stuff from scratch.
We can and should revisit this code, but for now, let's simply restore the behavior of HEAD, which should be easily possible by calling
Settings::confPath()andSettings::initialize()in sequence.AFAIK, a lot of people will disagree with this.
I looked through the patch but wasn't able to see why we suddenly have to tamper all PHPUnit test environments now.
Also note that I had removed all off-topic/out-of-scope changes regarding DRUPAL_ROOT from this patch in an earlier iteration already...
Minor: Let's simply vertically align each of these chained calls below each other (like we do everywhere else) ;-)
Comment #149
msonnabaum commentedI'm really disappointed to see that DrupalKernel::createFromRequest() is gone. I also don't see an explanation of why we're passing the request to boot() instead. Can someone explain why we did that?
Comment #150
neclimdulsimple answer, simpletest.
longer answer, it grep more complex, gained a singleton, got renamed to bootKernle() then backlash removed it entirely. I'm going to take a stab at bringing it back and seeing if it can take request out of boot. We'll see how far it gets.
Comment #151
msonnabaum commentedOk, great. I think it's well worth doing design-wise. Having the factory that takes a request separate from the boot/handle process is a very useful distinction that is quite muddy in the current patch.
Also, the name createFromRequest is perfect. bootKernel is considerably less clear.
Comment #152
mile23There shouldn't be a 'boot' method.
There should be a kernel object, and you tell it to do the thing you want to do, like this: https://github.com/symfony/symfony-standard/blob/master/web/app.php#L26-L29
Similarly, there shouldn't be a factory method that creates a kernel based on a request. That's silly. There's only one kind of kernel you can ever create, which is why it's the kernel.
Also, static methods::bad, testable methods->good.
Comment #153
msonnabaum commentedNo, there should be a boot method, and it should get called before the request is handled, without the context of the request. Your example doesn't show what you think it shows:
https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Htt...
For the love of god, please don't repeat nonsense like this. Static methods are not *bad*. It's a factory method. It's no less testable than a factory class.
Comment #154
neclimdulOk, createFromRequest() factory method, documentation changes from sun's pull. Also, from feedback from Mark I moved the conf_path replacement to DrupalKernel::sitePath(). Name change my design though because its more accurate. Move because Settings is a value object and it was actually that way in earlier patches.
The only thing I think I didn't do was sun's point #8 about indentation. There's documentation attached to it and the other places we indent on the same line we do because we're chainging
$thisreturns but this line changes to a request object. The indentation calls out the object change.Comment #155
moshe weitzman commentedI read through this *again* and its still awesome.
Thanks for the countless rerolls, @neclimdul.
Comment #156
webchickLet's try to cut down on the endless re-rolls.
Comment #158
tim.plunkettConflicted with #2228215: Remove module check in DrupalKernel :(
Which to add insult to injury, was committed, reverted, and committed despite this being tagged "avoid commit conflicts".
EDIT: Also conflicted with #2259275: Rename "DrupalUnitTestBase" to KernelTestBase, but AFAIK that was just a rename.
Comment #159
effulgentsia commentedThis is an attempt at a merge with 8.x, but I'm not familiar with the patch so may have resolved some conflicts incorrectly. Feel free to ignore and merge from scratch if this isn't useful.
Comment #161
neclimdulyeah... figured it might come back red. Thanks for trying though! Those where going to be another tricky merges but I'm working on it.
Comment #162
donquixote commentedRelated idea:
#2272129: [meta] Introduce a low-level DIC to organize low-level services
Comment #163
alexpottMissing doc blocks and I'm not sure of the point of this method. Yes it is called once but this is the onlt place $this->sitePath is set or accessed. I think it can be removed and the call to it. But what this means is that we've lost the static caching of the procedural conf_path() method. I don't know the performance impact of this because I don't know the amount of times this needs to be accessed per request.
Comment #164
neclimdulThink this gets all the fixes. There are some subtle changes to WebTestBase, mostly that it has to be able to dump the container to disk during rebuildContainer() now because the request won't automatically fix the container.
Good catch in a complicated patch alex. I though I should just kill it then looked at the number of calls to conf_path() and went ahead and documented it and added a get method. Also documented the deprecation noticed on conf_path(). I figure the individual conversions will know whether there's a kernel available or if it needs to build the path directly from a request like in the installer and choose the correct method. these changes are in the not-really-an-interdiff interdiff.
Comment #165
neclimdulIn my mind i changed the status. d.o disagrees though.
Comment #167
neclimdulunmerge merge with #2239969: Session of (UI) test runner leaks into web tests. revert cause patch apply to fail.
Comment #169
catchAre there any new classes that might get autoloaded from this before the APC classloader can be initialized?
Comment #170
neclimdulnew Patch.
catch, that came up at one point but I don't have the list. I'll come back shortly with the numbers but want to get testbot running.
Comment #171
neclimdulecho $class . "\n";on first line of composers classloader. Not many surprises here. Classes and interfaces are those related to the kernel with the exception of Timer which was moved earlier at moshe's request and Unicode who's ::check() call I moved to the environment initialization for clarity.Head:
Patch:
Comment #172
neclimdulMerge namespace conflict. Alex and Catch, any thoughts?
Comment #173
ParisLiakos commentedOverall this looks great!
Most of those below are nitpicks, couldnt find something wrong..i am not very sure about the introduction of
Settings::initialize()but we can revisit later if neededwould be nice to return $this here.
seems the negotiator is unused. remove?
unneeded?
Needs inheritdoc and strtoupper on true
irrelevant?
Unneeded indentation. also maybe have send() in separate line as well.
why not a RedirectResponse?
Lets also remove more require statements here:) there will be loaded in boot()
Comment #174
neclimdul1) I'm not sure why. That doesn't seem to be something we do on setters.
2) fixed.
3) yeah, missed those. fixed.
4) fixed.
5) Came up before. As is standard with chaining, indentation is used to show the change in the object being interacted with. This is also in the documentation to make it even more clear.
6) That's actually the way it already is in core and we're in such a limited environment in that script and there isn't any code to interact with the response so I didn't see a reason to change it and add the complexity.
7) Changing update.php makes me really nervous. Done, lets hope it comes back green. :)
Comment #175
moshe weitzman commentedNice work! Back to RTBC
Comment #176
neclimdulParis hit me up in IRC and pointed out there was a dead constructor argument in the service file. Quick fix.
Comment #177
catch#171 let's fix the extra file i/o before this goes in. Manual require somewhere would do it.
Comment #178
alexpottThe information in the issue summary is not up-to-date eg.
DrupalKernel::confPath()does not exist.I think there is a lot of potential confusion between getSitePath() and sitePath(). Not really what to do here. At least we need to document when to use which.
If we are going down the route of putting this functionality on the kernel then...
Should use $kernel->getSitePath()
Comment #179
znerol commentedReadability could be improved by not chaining if return values differ. E.g.:
Comment #180
alexpottWhat is the normal $conf_path now? :)
Plus to keep us honest I think this patch needs to refactor the use of conf_path in the kernel. Specifically
since this exposes a problem - this occurs during DrupalKernel::boot() and $this->sitePath might not be set. I don't think we should allow booting without this property being set.
Patch attached tries to address these problems.
Comment #182
alexpottSo we actually have no need to boot the Kernel in token rebuild script.
Comment #184
neclimdulAfter talking to catch, bumped #2253593: Stop classloader searching filesystem for classes before drupal_classloader() is called to major as a follow up.
Comment #185
alexpott182: 2016629.182.patch queued for re-testing.
Comment #186
neclimdulComment #187
neclimdulNoticed while updating the summary that the request_path() deprecation had sort of fallen out of scope. Rather than expanding the patch at the last minute to actually deprecate it, I just took it out.
Comment #188
neclimdulum... patch
Comment #189
neclimdulFix APC loader... Subtle bug, the argument to drupal_classloader() should probably be looked at, it doesn't really make sense.
Comment #190
neclimdulFix conflict in core.services.yml. Just diffs that where too close to merge, no changes from previous patch.
Comment #191
neclimdulDoing a once over again before asking for another RTBC and noticed a performance regression. Module loading was moved too early and was happening before the page cache calls. Moved it to the post page cache preHandle() method. Also took preHandle() out of the page cache step. Can't see a reason to and it moved that code earlier then it previously ran.
If this comes back green, which I'm fairly confident it will, we should have addressed all the reviews and be back to RTBC.
Comment #193
neclimdulOh simpletest... Seems that was needed for simpletest to run but luckily we made a test runner kernel so we can handle that now.
Comment #195
neclimdulThere's the reason preHandle was called in handlePageCache(), settings up the session/cookies. We can work around that until session is handled through the container.
Rather than bootstraping the legacy globals, I just converted the session_name code to use $request.
Comment #197
neclimdulBring over installer redirect hack.
Comment #199
neclimdulnot sure why that patch failed. Must have messed up creating it. New patch, no changes.
Comment #200
neclimdulComment #201
donquixote commentedReroll and fix a conflict in
core/modules/simpletest/src/KernelTestBase.php:Resolved like this (both were needed):
And btw, this method call in KernelTestBase is broken, since long before this patch:
unregisterStreamWrapper() requires two arguments: $scheme, $type.
Comment #202
donquixote commentedSee #2279213: KernelTestBase::unregisterStreamWrapper() is called once with insufficient arguments
Comment #203
msonnabaum commentedI profiled this and didn't find a big difference. It was hard to get a stable wall time with and without the patch, but just looking at the function call difference, it was mostly autoloader from new classes being introduced.
Just to make sure the difference is as insignificant as I thought it was, I did 100 samples with microtime of patch/nopatch and cached page/non-cached page.
Here are the results from that:
Comment #204
donquixote commentedIn DrupalKernelInterface:
I don't quite get why a static method needs to be part of the interface.
And in KernelTestBase::setUp()
Why the dynamic call to a static method? 3 lines up you see it is a DrupalKernel and nothing else..
Do we assume that test kernels will have their own implementation of findSitePath() ?
EDIT:
Got it, there is TestKernel::createFromRequest() and TestRunnerKernel::createFromRequest().
EDIT II: Duh, that's a different method..
Comment #205
neclimdulThat's pretty fair. That's a specific implementation relevant to using DrupalKernel and the internal DrupalKernel methods.
Comment #206
effulgentsia commentedI haven't reviewed the full patch, but all the interdiffs from #177 to #205 look good, except:
Huh?
Comment #207
neclimdulyeah... incomplete. @see interdiff.
Comment #208
donquixote commentedIn
DrupalKernel::handlePageCache():I have mixed feelings about this kind of control flow disruption. If you call a method, you don't expect the request to exit.
What if instead we would return the response and let the caller send it? E.g. index.php could do this:
But we could solve this in a follow-up.
Comment #209
znerol commentedRe #208: The page cache indeed needs an overhaul but there is already an issue for that: #2257695: [meta] Modernize the page cache
Comment #210
neclimdulThere are several issues looking at it I think which is why I just implemented the most straight forward options for frontend controllers and left it to those issues to solve. The chaining was very easy to call and left some API options available to those follow ups.
Comment #211
effulgentsia commentedPer #206, I haven't reviewed the whole patch. But, this was RTBC in #176, and AFAICT, all feedback since then has been addressed or has a separate issue filed. Therefore, back to RTBC.
Comment #212
catchCommitted/pushed to 8.x, thanks!
Comment #213
larowlanPublished change notice
Thanks @neclimdul and @sun for bringing this home
Comment #214
andypostFiled follow-up #2280383: FIx settings.local.php after new bootstrap
Comment #215
tstoecklerSee you in #2280501: Ensure web tests are encapsulated :-(
Comment #216
tstoecklerAs discovered in #2280383: FIx settings.local.php after new bootstrap this needs an additional change notice for the rename of
$conf_pathto$site_pathin settings.php.Comment #217
alexpottI've reverted the commit due to #2280501: Ensure web tests are encapsulated as this issue will cause significant problem's for tomorrow's sprint.
Comment #218
neclimdulI think this probably tracks back to refactoring around #2228215: Remove module check in DrupalKernel. That issue added some real complexity that's been troublesome for this issue.
Comment #219
znerol commented@neclimdul: Can you pinpoint the problem introduced by #2228215: Remove module check in DrupalKernel which you think is holding back this issue?
Comment #220
neclimdulThe entire patch sadly. The hacks it did detected tainted containers better. Also, allowLoading is really painful, especially when what we really want is a way to force rebuilds, especially in tests. Trying to revert parts of it would be pretty complicated so I'm most of the way through refactoring the container build process to work a little smoother and support this patch better.
Comment #221
znerol commentedThe way it works currently in HEAD is that
$allow_loading</cod> is set to <code>FALSEand$allow_dumpingis set toTRUEwhen (re-)building the test container. This ensures proper synchronization between the simpletest parent and child site.In fact we only should attempt to load the container from disk when it is built for the very first time in a request. In contrast we always should dump it whenever a service definition changed. It follows that during test-setup in the parent site, we must not allow loading of the container from disk. However, we need to ensure that modules enabled in the parent site will propagate to the child site. This is the reason for the following line (which is removed in the patch and for which I cannot find a substitution):
Still I cannot think of an explanation how #2228215: Remove module check in DrupalKernel should have caused #2280501: Ensure web tests are encapsulated.
Comment #223
David_Rothstein commentedWhile this is rolled back, what's the rationale for removing drupal_handle_request()?
See #1831998: Reduce index.php for easier upgrading for why that was added, and in addition it's used three places in core currently (so removing it leads to a bit of code duplication).
Comment #224
donquixote commentedWould it be possible to not rebuild the container in the middle of something, and instead queue up any operations that would trigger a container rebuild? These rebuilds seem to be a major source of complexity, and make the system less predictable.
#2282217: [meta] Never replace the container while services are still in call stack.
Comment #225
Anonymous (not verified) commentedthe underlying source of instability is the slowness of symfony's DiC, which forces us to cache a monolithic, central-to-just-about-everything blob at the centre of Drupal.
if it wasn't unusably slow, we could just build it on each request.
if it wasn't completely monolithic, we could cache and rebuild bits of it, instead of the whole thing.
instead, we've done dance after dance after dance during the D8 cycle trying to work around it.
Comment #226
neclimdulSo, I made the decision that this issue was about re-factoring the bootstrap and kernel to work better together. A part of that has been the container building process because that's where most of the boot happens now and that happens in the kernel. That's why the other patches changes sort of broke some assumptions built into this patch.
So, based on that decision, I decided to do some "yak shaving" and dig into the process rather then hacking around the current setup or adding another hack into it. I reviewed where we where using the using the "allow_loading" argument and its in one of 2 places.
1) in the installer when we know there isn't anything to load.
2) When we are forcing the container to rebuild because we know the system has changed. Generally module installation, but in simpletest for a couple reasons. One of those is forcing a rebuild instead of loading the parent site container, as znerol noted was breaking the web test-runner.
Since what we wanted is to force rebuilding of the kernel, I added DrupalKernel::rebuildContainer(). With that, allow_loading no longer had a use case. Since the "newModules" variable was basically used to trigger rebuilds too that can go away. The only thing it would have been supporting was calling updateModules() before the kernel is booted and since that is a pretty straightforward use case I just force a rebuild if the internal moduleList has a value set during boot. This sort of brings back a concept from the other issue but still leaves out the support and complexity that was the purpose of the issue.
Comment #227
neclimdul@beejeebus I don't know, that would sort of be like saying "anything that uses the cache system to hide slowness and complexity is a problem". IMHO, the problem is that we where trying to use magic instead of exposing the functionality we needed.
@David_Rothstein yeah, I definitely had that in mind. But, this still keeps things simple, and better, bring our front controller closer inline with a Symfony kernel app. I would say the pageHandleCache() method is a _bit_ of a regression in the goals of that issue but it was necessary to expose the complexity that was there if we're going to properly deal with it. I guess that is to say, the goal of that issue was to enforce an interface where the implementation was hidden from index.php. I think this still conforms to that goal.
Comment #228
neclimduloh, NR
Comment #230
znerol commentedFrankly I'd prefer the explicitness and clarity of
$allowLoading. However, if it is necessary to remove it as part of this patch, then I'm okay whit it. Given that this is touchingDrupalKernel::initializeContainer()now, please consider looking into whether you can borrow some of the ideas from #2281903: Refactor DrupalKernel::initializeContainer in preparation of a replacement for persist services.Comment #231
mile23I'd just like to point out some of the issues I've encountered while working on #2242947: Integrate Symfony Console component to natively support command line operations, since all of the design problems in this issue are pushed into stark relief on that one.
The console is implemented as a separate 'console application' object. It has to discover console commands, which live in a separate conceptual space from Drupal proper.
This means that there is a command discovery phase which occurs before the container is built, or the kernel is booted. This discovery phase is necessary since not all console commands will need a kernel or even a container.
In an ideal world, I'd be able to leverage the discovery system of the container for this task. But I can't because I'm not sure whether there are rules about the dependencies of either the container or the services within it.
That is, if I were to decide that all the commands should be services, and if I built a container as a way of doing discovery, are there rules about other services which will prevent them from, for instance, needing a database? I want my console commands to work regardless of installation state of the current Drupal. There is no documentation on requirements for services that I can find.
In the case of the console, the kernel is just another service that can be offered to a console command. This is similar to the need for a special-case booted kernel for testing purposes. It seems like solving one would solve the other.
Given all this, I think the scope of this issue should change. The goal of this exercise should be to allow a few of the following things to happen. Choose one or two and start work. :-)
1) Allow the kernel to be bootstrapped into an arbitrary environment, with different settings per environment (similar to Symfony's app_dev/test/prod.php.)
2) Formalize the dependency requirements of services. Can they need a database? Can they require a writable file system?
3) Decouple the container from the kernel. Allow me to make a container without a kernel.
See also: #2282779: [meta] DrupalKernel has too many responsibilities
Comment #232
neclimdulGetting back on this. Re-roll to get this applying and I think fix the simpletest problem that got this reverted. The new tests in SimpleTestTest pass so lets see if anything else fails.
Haven't done anything with the other discussion, will have to read and refresh.
Comment #234
neclimdulOk, the refactor I did in #226 caused a bug in the container rebuild that broke persistent services and there was another that caused the simpletest rebuild not to run with the updated module list. I spot checked some of the failures and they where green so another test bot run to make sure they're all green.
Comment #236
neclimdulAnother go. Ran all the tests except the dreaded InstallUninstallTest because it was taking for ever but it looked like it was passing so that's good enough for some sleep.
To explain the rebuildContainer -> resetAll changes in the interdiff, they follow ModuleHandler::install() calls which is already rebuilding the container. What we wanted was to update the container property with that new container and we don't need to force a rebuild to do that, resetAll() does exactly that as well as flush any other possibly pesky caches. A nice follow up might be to have installModule and uninstallModule methods on webtest if we want to support this sort of behaviour.
Comment #237
neclimdulSo reading back, znerol stated he would be ok with the container rebuild changes and I hope I addressed David's concerns about
drupal_handle_request()and I couldn't find anything actionable in Mile23's comment that wouldn't fit better in follow ups so I hope that means we're back to RTBC?Comment #238
moshe weitzman commentedYes, thats how I read the history as well. Thanks @neclimduhl. This was committed once already, but then reverted. Lets get this one in!
Comment #239
mile23@neclimdul: Thanks for inclusion. RTBC and happy. :-)
Comment #240
webchickAwesome work, folks. Sending to catch for final approval, since he committed it the first time around.
Comment #242
catchHad a look through all the interdiffs since the patch got committed. I agree with beejeebus' comments on the container - we're using it for a purpose it absolutely was not designed for (including ContainerBuilder which is officially supposed to be 'development mode') and as such it represents a large and fragile dependency (ba-doom-tish) right at the middle of the system.
However this issue is if anything clarifying the issues around that, certainly not making anything worse.
Committed/pushed to 8.x, thanks!
Comment #243
yched commentedNot sure if it's related, but I currently get
Exception: Kernel does not have site path set before calling boot() in core/lib/Drupal/Core/DrupalKernel.php on line 374
on visiting core/rebuild.php ?
Comment #244
jibranrun the update.php first it'll fix the error.
Comment #245
yched commentedI see this on a fresh install :)
Comment #246
Anonymous (not verified) commentedre. #243, me too.
Comment #247
neclimdulQuick follow up, rebuild.php is totally broken. However, nothing else coudl be broken this was because nothing else instantiates the kernel outside of CreateFromRequest and could miss the requirement to set the site path on the kernel. The other option is we could inject a kernel into
drupal_rebuild()now instead of classloader and request since we can delay boot. That wasn't a thing whendrupal_rebuild()was initially refactored.Comment #248
andypostdrush crbroken tooComment #249
neclimdulI wish i knew why sometimes my patches don't shop up...
Comment #250
Anonymous (not verified) commentedtested the patch, and it fixes the fatal for me.
Comment #251
andypostyep, but drush should be fixed here
Comment #252
catchCommitted/pushed the follow-up, thanks!
Comment #254
yched commentedOpened https://github.com/drush-ops/drush/issues/691 for "drush cr" earlier today.
I guess it's up to Drush folks to chime in whether @neclimdul alternative proposal in #247 makes sense for them ?
Comment #256
znerol commentedFiled #2344017: All modules loaded in authorize.php, not sure about the consequences.
Comment #257
xjmComment #258
quietone commentedPublished change record