Problem/Motivation

Follow-up to #1827112: Convert 'install_profile' variable to Settings. Drupal 8+ really wants a valid value of install_profile in settings.php by the end of installation. Therefore, it tries to write it at end of installer. If settings.php is read-only, install will fail with an exception misleadingly explaining that settings.php must be writable. But making this file writable is not possible in many hosting environments.

Proposed resolution

Only require a value for install_profile when this information cannot be derived otherwise. When a site is running a Distribution (note the special key in the yml), we can derive the install_profile name.

Remaining tasks

None

User interface changes

None

API changes

Settings::installProfile() is now preferred over drupal_get_profile() which is marked as deprecated.

Data model changes

None

Beta phase evaluation

Reference: https://www.drupal.org/core/beta-changes
Issue category Bug because Drupal is not installable in environments where it used to be.
Issue priority Major because many hosts (Pantheon, Acquia, etc.) will have pain here because they default to more secure installations (non-writable settings.php
Disruption Not disruptive because only affects the installer, not module code.
CommentFileSizeAuthor
#216 210-216-interdiff.txt1015 bytesalexpott
#216 2156401-3-216.patch50.34 KBalexpott
#210 2156401-4-210.patch50.27 KBalexpott
#210 202-210-interdiff.txt6.16 KBalexpott
#202 2156401-3-202.patch50.14 KBalexpott
#202 196-202-interdiff.txt585 bytesalexpott
#196 write_install_profile-2156401-196.patch50.07 KBManuel Garcia
#188 2156401-3-188.patch50.26 KBalexpott
#183 177-183-interdiff.txt4.64 KBalexpott
#183 2156401-3-183.patch50.08 KBalexpott
#177 2156401-3-177.patch51.22 KBalexpott
#177 176-177-interdiff.txt1.2 KBalexpott
#176 2156401-3-176.patch51.23 KBalexpott
#176 175-176-interdiff.txt1.09 KBalexpott
#175 2156401-3-175.patch51.62 KBalexpott
#175 170-175-interdiff.txt5.97 KBalexpott
#170 2156401-3-170.patch53.99 KBalexpott
#170 165-170-interdiff.txt6.14 KBalexpott
#165 2156401-3-165.patch52.19 KBalexpott
#165 164-165-interdiff.txt634 bytesalexpott
#164 2156401-3-163.patch52.19 KBalexpott
#164 162-163-interdiff.txt4.27 KBalexpott
#162 2156401-3-162.patch51.18 KBalexpott
#162 160-162-interdiff.txt19.33 KBalexpott
#160 interdiff.txt1.82 KBdawehner
#160 2156401-160.patch48.22 KBdawehner
#158 2156401-3-158.patch49.59 KBalexpott
#158 155-158-interdiff.txt1.31 KBalexpott
#155 2156401-3-154.patch48.73 KBalexpott
#155 150-154-interdiff.txt3.65 KBalexpott
#153 2156401-3-153.patch141.04 KBalexpott
#153 150-153-interdiff.txt2.38 KBalexpott
#150 interdiff.txt6.82 KBdawehner
#150 2156401-149.patch45.02 KBdawehner
#147 interdiff-2156401-144-147.txt1.73 KBphenaproxima
#147 2156401-147.patch47.18 KBphenaproxima
#144 2156401-144.patch47.03 KBbalsama
#144 interdiff-2156401-142-144-do-not-test.diff4.3 KBbalsama
#142 2156401-2-142.patch46.27 KBalexpott
#131 128-131-interdiff.txt3.2 KBalexpott
#131 2156401-2-131.patch46.29 KBalexpott
#129 interdiff-128-w-114.txt4.02 KBgreg.1.anderson
#128 2156401-128.patch47.14 KBgreg.1.anderson
#123 2156401-123.patch46.99 KBgreg.1.anderson
#121 2156401-120.patch47.05 KBgreg.1.anderson
#114 drupal-avoid_writing-2156401-114.patch51.12 KBheddn
#112 drupal-avoid_writing-2156401-112.patch49.75 KBheddn
#100 2156401_100.patch46.21 KBtedbow
#100 interdiff-97-100.txt8.84 KBtedbow
#97 2156401_97.patch45.74 KBtedbow
#97 interdiff-94-97.txt14.64 KBtedbow
#94 2156401_94.patch39.9 KBtedbow
#94 interdiff-92-94.txt787 bytestedbow
#92 interdiff-90-92.txt847 bytestedbow
#92 2156401_92.patch39.13 KBtedbow
#90 2156401_90.patch39.05 KBMile23
#87 interdiff.txt8.7 KBdawehner
#87 2156401-87.patch38.39 KBdawehner
#84 2156401-78.patch40.18 KBchris.smith
#81 2156401-77.patch40.9 KBchris.smith
#77 2156401-76.patch41.05 KBchris.smith
#75 interdiff-2156401-73-75.txt732 bytesphenaproxima
#75 2156401-75.patch40.61 KBphenaproxima
#73 2156401-73.patch40.62 KBphenaproxima
#67 avoid_writing-2156401-67.patch41.4 KBizus
#62 avoid_writing-2156401-62.patch41.14 KBmoshe weitzman
#60 avoid_writing-2156401-60.patch41.67 KBmoshe weitzman
#57 2156401.57.patch40.92 KBalexpott
#57 53-57-interdiff.txt11.36 KBalexpott
#53 2156401.52.patch34.1 KBalexpott
#53 44-52-interdiff.txt7 KBalexpott
#44 2156401.43.patch29.59 KBalexpott
#44 40-43-interdiff.txt12.82 KBalexpott
#15 tolerate.diff3.29 KBmoshe weitzman
#17 avoid_writing-2156401-17.patch6.22 KBmoshe weitzman
#20 avoid_writing-2156401-19.patch6.55 KBmoshe weitzman
#20 interdiff.txt2.05 KBmoshe weitzman
#23 avoid_writing-2156401-23.patch7.4 KBmoshe weitzman
#23 interdiff.txt866 bytesmoshe weitzman
#27 read-only-settings-install-error.png127.49 KBgreg.1.anderson
#34 settings-2156401-34.patch7.24 KBxjm
#34 spinach-interdiff.txt3.06 KBxjm
#34 spinach-interdiff.txt3.06 KBxjm
#37 34-37-interdiff.txt11.94 KBalexpott
#37 2156401.37.patch11.53 KBalexpott
#38 37-38-interdiff.txt6.8 KBalexpott
#38 2156401.38.patch16.08 KBalexpott
#40 38-40-interdiff.txt4.82 KBalexpott
#40 2156401.40.patch18.83 KBalexpott
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

sun’s picture

sun’s picture

As far as I can see, the same issue appears to apply to the "drupal_hash_salt" setting → if there is a working settings.php already, then the installer will not create a new hash salt.

Both the installation profile and the hash salt are values that ought to be written into settings.php upon every installation. Regardless of whether settings.php is functional already or not.

larowlan’s picture

What about config directories Conf?

sun’s picture

The installer rewrites settings.php already in case no valid config directories are defined yet.

However, the installer does not touch settings.php, if all of the following conditions are met:

1. settings.php exists
2. Valid $databases and database connection
3. Valid $config_directories

In that case, the entire settings processing step of the installer is automatically skipped.

See install_tasks():

    'install_settings_form' => array(
      'display_name' => t('Set up database'),
      'type' => 'form',
      // Even though the form only allows the user to enter database settings,
      // we still need to display it if settings.php is invalid in any way,
      // since the form submit handler is where settings.php is rewritten.
      'run' => $install_state['settings_verified'] ? INSTALL_TASK_SKIP : INSTALL_TASK_RUN_IF_NOT_COMPLETED,
    ),

That comment, and the corresponding $install_state['settings_verified'] was meant to be a unique condition and trigger for invoking the settings form - either with an interface, or just programmatically, depending on whether the database is configured correctly already.

However, install_begin_request() only cumulates the following conditions:

  $install_state['config_verified'] = install_verify_config_directory(CONFIG_ACTIVE_DIRECTORY)
                                   && install_verify_config_directory(CONFIG_STAGING_DIRECTORY);
  $install_state['database_verified'] = install_verify_database_settings();

  $install_state['settings_verified'] = $install_state['config_verified'] && $install_state['database_verified'];

That is the location in which all conditions for a potential rewrite of settings.php have to be specified.

However, given that the new $settings['install_profile'] is almost guaranteed to be different for each installation, we might as well decide to remove the entire conditionals and always execute the settings form.

That would ensure that "install_profile" and "drupal_hash_salt" are always written to settings.php for each (re-)installation of Drupal.

Thoughts?

larowlan’s picture

Also #2115533: Add InstallerInterface to provide a stable non-interactive installer
I don't see a problem with that although I note that the interactive installer test assumes you can skip at least the language and profile steps, not sure about the settings.

sun’s picture

The new InstallerExistingSettingsTest discovered that the "Set up database" form (install_settings_form()) appears even if settings.php contains a valid database connection already but e.g. no config directories yet.

That's a slightly different symptom, but identical root cause:

The form has to be skipped in the UI, but still needs to be executed, so that settings.php gets rewritten.

Alternatively, we could investigate whether it wouldn't make sense to split this step into two:

  1. A pure UI form to provide database connection info, and whose submit handler effectively does nothing.
  2. A new install_rewrite_settings() install task that explicitly rewrites settings.php.
sun’s picture

Assigned: Unassigned » sun

Guess I should put this into my bucket...

alexpott’s picture

moshe weitzman’s picture

Assigned: sun » Unassigned
Status: Closed (duplicate) » Active

This issue was not fixed by #2451363: Ensure install_profile is exists in settings.php after installation at least for the non-interactive installer (i.e. Drush). So I am reopening. To reproduce the problem, install first with minimal and then with standard (or vice versa). You end up with the old profile only in settings.php.

In Drush, we are going to just refuse to proceed with re-install in this situation and leave the fix to this issue - https://github.com/drush-ops/drush/pull/1345

alexpott’s picture

Ah it was fixed by at one point. But then we backed off one of the changes for some sensible reason.

alexpott’s picture

Actaully I've just run the test myself and the value is changed - are you sure about this?

alexpott’s picture

And if I change settings.php to something unwritable I get an error if the profiles don't match.

greg.1.anderson’s picture

Seems I was having trouble with this just last week. I'll re-run the tests and confirm here.

moshe weitzman’s picture

Title: install_profile setting is not written to settings.php when re-installing » install_profile mismatch is poorly reported during a re-install

alexpott is right and this is working for me as designed.

  1. We can still improve the UX when there is a mismatch and settings.php is non-writable. The error tells you to make settings.php writable. It says nothing about the install_profile mismatch. In Acquia's case, it is likely that the customer has to change the value of install_profile, commit to git, and deploy, since our settings.php is never writable. Lets repurpose this issue for this item.
  2. Drush drops all your tables and then you rudely find out about the mismatch. Lets handle that in https://github.com/drush-ops/drush/pull/1345
moshe weitzman’s picture

Attached patch skips reporting an error when the distribution can be determined purely via code. This is a big help in environments where settings.php is usually read-only.

I still would like a better error message when we fail to write to settings due to a profile mismatch. I'm not sure yet how to reliably catch that exception. That can be a follow-up, IMO

moshe weitzman’s picture

Title: install_profile mismatch is poorly reported during a re-install » Avoid writing install_profile value to settings.php when provided by a Distribution
Priority: Normal » Major
moshe weitzman’s picture

Status: Active » Needs review
FileSize
6.22 KB

@alexpott suggested that we replace all calls to Settings::get('install_profile' with a new Settings::getInstallProfile() which implements the fallback to a Distribution. Its a good idea - the attached patch does just that.

Berdir’s picture

  1. +++ b/core/lib/Drupal/Core/Site/Settings.php
    @@ -150,6 +150,22 @@ public static function getHashSalt() {
    +   * Get the configured install profile, or fall back to the first Distribution
    +   * that was declared. If neither is available, return NULL.
    

    First part of a docblock should be < 80 characters and a single line.

    No need to have all this information here, the last sentence can be moved to the @return, and the second part also seems unecessary here (it's an implementation detail and not relevant for the caller IMHO)

  2. +++ b/core/lib/Drupal/Core/Site/Settings.php
    @@ -150,6 +150,22 @@ public static function getHashSalt() {
    +  public static function getInstallProfile() {
    +    $install_profile = self::$instance->get('install_profile');
    +    if (empty($install_profile)) {
    +      $install_profile = drupal_get_distribution();
    +    }
    +
    +    return $install_profile;
    +  }
    

    Do we get multiple calls to this? Should we statically cache it, or put it inside settings when it's not set?

Should we deprecate drupal_get_profile() in favor of Settings::getProfile()? I also don't really like adding new functions...

Status: Needs review » Needs work

The last submitted patch, 17: avoid_writing-2156401-17.patch, failed testing.

moshe weitzman’s picture

Status: Needs work » Needs review
FileSize
6.55 KB
2.05 KB

Addressed all feedback except for getting rid of drupal_get_profile(). Instead I marked it as deprecated. I can't get rid of it without bringing along its special case for the installer. Since there are 18 callers and we are late in the cycle, I figure we can leave it as a wrapper for now.

alexpott’s picture

Status: Needs review » Needs work
Issue tags: +Needs tests

I think that this is testable by creating an InstallerTestBase test and having it create the test distribution... oh we have this already - DistributionProfileTest. We should test this is that test.

moshe weitzman’s picture

Status: Needs work » Needs review
FileSize
7.4 KB
866 bytes

Added an assertion to DistributionProfileTest. Thanks for the pointer.

moshe weitzman’s picture

Issue tags: -Needs tests
pwolanin’s picture

So, am I missing something or is this going to do a file scan on every page load if you don't have the setting in place?

It also seems like it won't fall back to standard if nothing is set in settings.php?

Would be helpful to update the summary about what the current proposed resolution is and what problem it's trying to solve.

moshe weitzman’s picture

@pwolanin - i clicked around and can't find any regular pages that call Settings::getInstallProfile(). I think this only happens during Drupal heart attacks like cache rebuilds. During page building, Drupal relies on the config item core.extension which already includes your profile.

I don't think fallback to Standard is appropriate. For one thing, the installer would just pick Standard in that case, and not present a chooser.

I updated the Issue Summary and added Beta Eval

greg.1.anderson’s picture

I tried applying this patch to Drupal 8.0-beta12, and installing on a system with a read-only settings.php file, and still received an error:

Cannot write settings.php

greg.1.anderson’s picture

I tried running Drupal 8 with this patch installed, with a writable settings.php, and the install profile line was still written to settings.php. It seems like this is expected behavior for this patch -- we are only trying to make Drupal still install if the install profile line does not exist in settings.php.

However, I have not yet been successful in making this work when settings.php is not writable, even with a couple of experimental changes to try to help things along. I'll keep trying, though.

moshe weitzman’s picture

Issue summary: View changes
greg.1.anderson’s picture

Status: Needs review » Reviewed & tested by the community

Ok, I now see that this patch is only for sites with distributions. Testing #23 on Drupal 8 beta 12 with a distribution works like a charm. This is a great improvement for hosting environments that want to set up their configuration in advance via a read-only settings.php.

The last submitted patch, 15: tolerate.diff, failed testing.

greg.1.anderson’s picture

Once this is committed, as a next step we could modify #1356276: Allow profiles to define a base/parent profile to favor the distribution that contains a 'base' attribute (inherits from some other distribution).

moshe weitzman’s picture

Assigned: Unassigned » alexpott

Note that #31 is a false negative. The bot tested an ancient patch.

Since alexpott looked at this once already, I'm assigning this to him. My apologies if that is bad form.

xjm’s picture

Assigned: alexpott » Unassigned
Issue summary: View changes
Status: Reviewed & tested by the community » Needs review
Issue tags: +Needs change record
FileSize
7.24 KB
3.06 KB
3.06 KB

Thanks Moshe, and thanks Greg for the manual testing!

Since @alexpott most recently just asked for tests I don't think it specifically needs his feedback, so unassigning. However, each time I started to review this I got snagged on miscellaneous spinach that seemed a smidge too much to fix on commit, so attached cleans that up a little. I'd leave it at RTBC since these are utterly tedious coding standards fixes, but it also needs a change record since it includes a deprecation, so NW for the CR once the bot picks it up.

Also fixing a typo or two in the beta eval. It's listed not disruptive but would be good to say why; presumably because it's totally BC/API addition and only affects sites when they are first being installed.

Finally, I'm still a little concerned about #25. Extra file scans even just on cold cache sound worrisome. I think we should confirm that there isn't a performance issue being added here.

xjm’s picture

Status: Needs review » Needs work
Issue tags: +needs profiling

And NW for the CR.

moshe weitzman’s picture

Issue summary: View changes
Status: Needs work » Reviewed & tested by the community
  1. Added justification for Not Disruptive in the CR.
  2. A full cold cache rebuild is already horribly slow. These file scans are trivial compared to all the other cache calculating we need to do at this time. Sites under significant load are probably going to do a cache warming step before going live. Thats not affected by this patch.

Back to RTBC. Hope thats OK. There have been no changes to the patch itself.

alexpott’s picture

Status: Reviewed & tested by the community » Needs review
FileSize
11.94 KB
11.53 KB

It's not just cold cache that would need the additional disk access but going to a page like admin/modules would end up calling drupal_get_distribution() if the install profile is not written to settings.php.

So... I think we can actually make this work with container parameters - which means that the installer logic in install profile can be moved to InstallerKernel (hey this makes sense) - and the install profile ends up being written to the container.

An interdiff is attached but it might be best to just read the patch since it's a big change of approach.

alexpott’s picture

Now with added tests that if we have an existing unwritable settings.php the installer works and the install_profile is correctly determined without being written to settings.php.

The last submitted patch, 37: 2156401.37.patch, failed testing.

alexpott’s picture

Look how the changes to GetFilenameUnitTest are so nice :) - no longer relying on the weird install_state global side effect for testing!

Renamed the container parameter from install.profile to install_profile cause it matches the existing setting. And tidied up a few things.

The last submitted patch, 38: 2156401.38.patch, failed testing.

Fabianx’s picture

Looks really great, I would RTBC this - but I am not sure if alexpott does not want to work more on this.

dawehner’s picture

  1. +++ b/core/lib/Drupal/Core/DrupalKernel.php
    @@ -1079,6 +1080,7 @@ protected function compileContainer() {
         $container->setParameter('container.modules', $this->getModulesParameter());
    +    $container->setParameter('install_profile', $this->getInstallProfile());
     
    
    +++ b/core/lib/Drupal/Core/InstallProfileFactory.php
    @@ -0,0 +1,42 @@
    +  public function get() {
    +    return $this->drupalKernel->getInstallProfile();
    +  }
    

    I don't see the point of that, isn't the parameter enough?

  2. +++ b/core/lib/Drupal/Core/DrupalKernelInterface.php
    @@ -134,4 +134,15 @@ public function preHandle(Request $request);
    +   * If multiple profiles are distributions, then the first discovered profile
    +   * will be selected. See https://www.drupal.org/node/2210443.
    

    That is a bit confusing, but I guess a distribution will never ship with two, I gues?

  3. +++ b/core/lib/Drupal/Core/InstallProfileFactory.php
    @@ -0,0 +1,42 @@
    + * Contains \Drupal\Core\AppRootFactory.
    ...
    +class InstallProfileFactory {
    

    Needs the right class

+++ b/core/lib/Drupal/Core/InstallProfileFactory.php
@@ -0,0 +1,42 @@
+ */
+class InstallProfileFactory {
+

I don't see the point of that at all, why is the parameter not enough? At least the factory docs should explain that, and when to use what

alexpott’s picture

I do... adding more testing around assumptions that Drush makes about being able to override profiles even if an existing Settings.php has one set in it. Also the test added for non writable settings.php and a distribution was not quite right. Patch adds plenty of tests for the various scenarios even one where the settings.php is not writable but we have a profile mistmatch and throw and exception in the installer.

alexpott’s picture

xjm’s picture

We still need a change record, also.

catch’s picture

Does the install profile really have to live in settings.php, could it live in state instead?

moshe weitzman’s picture

Status: Needs review » Reviewed & tested by the community

@catch - if nothing else, you are consistent :). See #1827112-39: Convert 'install_profile' variable to Settings where you asked same question. Then see #55 there where you declared settings.php to be the right place for this.

So, this looks RTBC to me as well.

I'm not sure what the CR would say here. install_profile was not written in D7. Further, any D8 sites in the wild are unharmed by removing the requirement to write this param.

dawehner’s picture

Status: Reviewed & tested by the community » Needs work

No, this issue has two needs tags and things aren't addressed. Just because you want that in doesn't mean its automatically RTBC :)

+++ b/core/lib/Drupal/Core/DrupalKernelInterface.php
index 0000000..dc6b9af
--- /dev/null

--- /dev/null
+++ b/core/lib/Drupal/Core/InstallProfileFactory.php

+++ b/core/lib/Drupal/Core/InstallProfileFactory.php
+++ b/core/lib/Drupal/Core/InstallProfileFactory.php
@@ -0,0 +1,42 @@

This is totally unused

moshe weitzman’s picture

Issue tags: -needs profiling

Sorry, I did not see those.

  1. In my last post, I asked a CR would say for this issue. Any input?
  2. As for profiling, what is imagined there? This is only in effect during container rebuild which is pretty much ignored from a profiling perspective AFAIK. Don't think this shallow file scan contributes in any significant way. I'm gonna be bold and remove this tag.
Fabianx’s picture

I agree that the newest approach does not need profiling, we do way worse things on container rebuild and/or module scan time.

dawehner’s picture

No worries @moshe weitzman (it was late at night)

I agree that the newest approach does not need profiling, we do way worse things on container rebuild and/or module scan time.

I totally agree

alexpott’s picture

Status: Needs work » Needs review
FileSize
7 KB
34.1 KB

I think the fact that the install profile should be injected into services is worthy of a CR (https://www.drupal.org/node/2538996). Very few services require this but doing this will allow new ways of unit testing them. In the patch attached I've used parameter injection in the ConfigInstaller so there is an example in core.

Patch attached also removes bogus InstallProfileFactory - sorry that crept in - it was a partial idea that I dropped because it was unnecessary complexity.

dawehner’s picture

What I really like about that approach is that there is a clear state whether the install profile is determined.

Fabianx’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: -Needs change record

Thanks for the PR, the patch looks really great now!

catch’s picture

Status: Reviewed & tested by the community » Needs review

This changes the behaviour in subtle ways that make me uncomfortable, it might be just a documentation issue, or it might be something we need to account for.

Consider:

1. You install a site with one distribution.

2. Later on you add a different install profile to /profiles, because you're updating your site to be a multi-site.

3. Because nothing is in settings.php, now the file scan finds the different distribution instead of the original one. Fun ensues.

With the current behaviour, once the install profile is in settings.php, it's fixed and changes to the filesystem don't mess with it.

Also wonder if since it's going into a container parameter, whether we can't use services.yml for distributions and fall back to that instead of the filescan. Not sure if that fixes the use case this is intended for though (i.e. whether the installations that don't want to write to settings.php also don't want to write to services.yml).

alexpott’s picture

We can throw an exception if this occurs after a site has been installed and if a site is installed with two distributions we can force the user to choose.

Status: Needs review » Needs work

The last submitted patch, 57: 2156401.57.patch, failed testing.

moshe weitzman’s picture

The new exception looks smart to me. I noticed the path core/lib/Drupal/Core/Installer and wondered if Installer is really the right place for this. getDistribution() is in core/lib/Drupal/Core/DrupalKernelInterface.php.

Also saw one typo: distrubtion

moshe weitzman’s picture

Status: Needs work » Needs review
FileSize
41.67 KB

Reroll for one conflict and fixed the remaining typo from ##5.

Status: Needs review » Needs work

The last submitted patch, 60: avoid_writing-2156401-60.patch, failed testing.

moshe weitzman’s picture

Status: Needs work » Needs review
FileSize
41.14 KB

Rerolled. No logic changes. Lets see what fails.

Status: Needs review » Needs work

The last submitted patch, 62: avoid_writing-2156401-62.patch, failed testing.

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 62: avoid_writing-2156401-62.patch, failed testing.

anavarre’s picture

Issue tags: +Needs reroll
izus’s picture

Status: Needs work » Needs review
FileSize
41.4 KB

Hi,
Here is a rerolled #60
:)

Status: Needs review » Needs work

The last submitted patch, 67: avoid_writing-2156401-67.patch, failed testing.

The last submitted patch, 67: avoid_writing-2156401-67.patch, failed testing.

opdavies’s picture

Issue tags: -Needs reroll

The patch in #67 applies cleanly to HEAD.

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 67: avoid_writing-2156401-67.patch, failed testing.

phenaproxima’s picture

Status: Needs work » Needs review
FileSize
40.62 KB

Re-rolled against #57 at @moshe weitzman's request.

Status: Needs review » Needs work

The last submitted patch, 73: 2156401-73.patch, failed testing.

phenaproxima’s picture

Status: Needs work » Needs review
FileSize
40.61 KB
732 bytes

I know nothing about the install system, but let me try this on a hunch...

Status: Needs review » Needs work

The last submitted patch, 75: 2156401-75.patch, failed testing.

chris.smith’s picture

Re-rolled.

Patch failed to apply after commit:
Commit 41e882f on 8.0.x

Still failing testing.

anavarre’s picture

Status: Needs work » Needs review

The last submitted patch, 73: 2156401-73.patch, failed testing.

The last submitted patch, 75: 2156401-75.patch, failed testing.

chris.smith’s picture

Fixing whitespace issue. Oops!

The last submitted patch, 77: 2156401-76.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 81: 2156401-77.patch, failed testing.

chris.smith’s picture

Status: Needs work » Needs review
FileSize
40.18 KB

Missed the new conditional in getProfileStorage(). Submitting re-roll for test again.

Status: Needs review » Needs work

The last submitted patch, 84: 2156401-78.patch, failed testing.

moshe weitzman’s picture

Anyone available to push this along? Only 4 fails.

dawehner’s picture

Status: Needs work » Needs review
FileSize
38.39 KB
8.7 KB

This fixes most of the points.

Status: Needs review » Needs work

The last submitted patch, 87: 2156401-87.patch, failed testing.

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Mile23’s picture

Status: Needs work » Needs review
FileSize
39.05 KB

Status: Needs review » Needs work

The last submitted patch, 90: 2156401_90.patch, failed testing.

tedbow’s picture

Status: Needs work » Needs review
FileSize
39.13 KB
847 bytes

This patch fixes an error in InstallerExistingSettingsMismatchProfileTest

It was attempting to override getInstallationUrl to pass parameters via the query string which I didn't see in the parent class or anywhere else.

Instead I changed it to override visitInstaller:

 protected function visitInstaller() {
    // Provide profile and language in query string to skip these pages.
    $this->drupalGet($GLOBALS['base_url'] . '/core/install.php?langcode=en&profile=testing');
  }

I am still seeing an failing test in InstallerExistingSettingsMismatchProfileBrokenTest

I am not sure what is happening. I see:

 protected function error($message = '', $group = 'Other', array $caller = NULL) {
    if ($group == 'Exception' && $message == $this->exceptionMessage) {
      // Ignore the expected exception.
      return FALSE;
    }
    return parent::error($message, $group, $caller);
  }

This is the first time I have looked at installer tests but this seem to be trying to suppress the know error.
Through putting in debug messages I can confirm that the return false is being hit but I still see the error causing a failing test.

Anyways hopefully this patch will cause 1 less failing test.

Status: Needs review » Needs work

The last submitted patch, 92: 2156401_92.patch, failed testing.

tedbow’s picture

Status: Needs work » Needs review
FileSize
787 bytes
39.9 KB

Ok here is patch that fixes one of tests to use \Drupal::installProfile()

Should fix 1 fail. Still not sure why the known error is not being suppressed as I mentioned in #92

Status: Needs review » Needs work

The last submitted patch, 94: 2156401_94.patch, failed testing.

dawehner’s picture

  1. +++ b/core/includes/bootstrap.inc
    @@ -715,31 +715,19 @@ function drupal_installation_attempted() {
    + * @deprecated in Drupal 8.0.0, will be removed before Drupal 9.0.0.
    

    Let's point to 8.2.x

  2. +++ b/core/includes/bootstrap.inc
    @@ -715,31 +715,19 @@ function drupal_installation_attempted() {
    + *   Use \Drupal::installProfile() or the install_profile container parameter
    + *   instead.
    

    Ideally we swap that around

  3. +++ b/core/lib/Drupal/Core/Config/ExtensionInstallStorage.php
    @@ -78,15 +77,14 @@ protected function getAllFolders() {
    -      $install_profile = Settings::get('install_profile');
    -      $profile = drupal_get_profile();
    +      $profile = \Drupal::installProfile();
           $extensions = $this->configStorage->read('core.extension');
           // @todo Remove this scan as part of https://www.drupal.org/node/2186491
           $listing = new ExtensionDiscovery(\Drupal::root());
           if (!empty($extensions['module'])) {
             $modules = $extensions['module'];
             // Remove the install profile as this is handled later.
    -        unset($modules[$install_profile]);
    +        unset($modules[$profile]);
    

    We can inject the profile into this class as well.

  4. +++ b/core/lib/Drupal/Core/DrupalKernelInterface.php
    @@ -140,4 +140,19 @@ public function preHandle(Request $request);
    +   * If multiple profiles are distributions, then the first discovered profile
    +   * will be selected. See https://www.drupal.org/node/2210443.
    ...
    +   * @throws \Drupal\Core\Installer\Exception\TooManyDistributionsException
    +   *   Thrown when a site has more than one distribution installation profile.
    

    Mh, don't those two lines disagree with each other?

  5. +++ b/core/lib/Drupal/Core/Installer/Exception/TooManyDistributionsException.php
    @@ -0,0 +1,16 @@
    +
    +/**
    + * @file
    + * Contains \Drupal\Core\Installer\Exception\TooManyDistributionsException.
    + */
    
    +++ b/core/modules/system/src/Tests/Installer/DistributionProfileExistingSettingsTest.php
    @@ -0,0 +1,165 @@
    +
    +/**
    + * @file
    + * Contains \Drupal\system\Tests\Installer\DistributionProfileExistingSettingsTest.
    + */
    
    +++ b/core/modules/system/src/Tests/Installer/InstallerExistingSettingsMismatchProfileBrokenTest.php
    @@ -0,0 +1,133 @@
    +/**
    + * @file
    + * Contains \Drupal\system\Tests\Installer\InstallerExistingSettingsMismatchProfileBrokenTest.
    + */
    +
    
    +++ b/core/modules/system/src/Tests/Installer/InstallerExistingSettingsMismatchProfileTest.php
    @@ -0,0 +1,106 @@
    +
    +/**
    + * @file
    + * Contains \Drupal\system\Tests\Installer\InstallerExistingSettingsMismatchProfileTest.
    + */
    
    +++ b/core/modules/system/src/Tests/Installer/MultipleDistributionsProfileTest.php
    @@ -0,0 +1,106 @@
    +
    +/**
    + * @file
    + * Contains \Drupal\system\Tests\Installer\MultipleDistributionsProfileTest.
    + */
    

    Let's not add all of them here.

  6. +++ b/core/modules/system/src/Tests/Bootstrap/GetFilenameUnitTest.php
    @@ -12,14 +13,18 @@
       /**
    +   * {@inheritdoc}
    +   */
    +  public function containerBuild(ContainerBuilder $container) {
    +    parent::containerBuild($container);
    +    // Use the testing install profile.
    +    $container->setParameter('install_profile', 'testing');
    +  }
    +
    

    Should we set this up in KernelTestBase itself?

tedbow’s picture

Status: Needs work » Needs review
FileSize
14.64 KB
45.74 KB

Ok here is patch that addresses @dawehner's review and

In InstallerExistingSettingsMismatchProfileBrokenTest the last line is new here.

public function testBrokenInstaller() {
    $this->assertRaw(Html::escape($this->exceptionMessage));
    // The exceptions are expected. Do not interpret them as a test failure.
    // Not using File API; a potential error must trigger a PHP warning.
    unlink(\Drupal::root() . '/' . $this->siteDirectory . '/error.log');
  }

After chatting with @wimleers he point this out to me. It is used when a known error is written out to error.log. Errors in would then be read in simpletest_log_read and add false failing test.

Also in \Drupal\Core\Config\ExtensionInstallStorage::getAllFolders changed

-        if (isset($this->profile)) {
+        if ($this->profile) {

Because \Drupal::installProfile() will return back a false if no profile is set yet I believe. But I am clear whether that would ever happen in this point in the install.

Status: Needs review » Needs work

The last submitted patch, 97: 2156401_97.patch, failed testing.

tedbow’s picture

Whoops! Think I see what I did wrong here. Another patch coming shortly.

tedbow’s picture

Status: Needs work » Needs review
FileSize
8.84 KB
46.21 KB

Ok this patch fixes those test errors by adding \Drupal\system\Tests\Bootstrap\GetFilenameUnitTest::containerBuild and removing the logic KernelTestBase.

This caused a bunch of tests to fail. Not sure why.

I also fixed some dependency injection issues from my last patch.

dawehner’s picture

This caused a bunch of tests to fail. Not sure why.

That honestly sounds like a problem for me. If the code which kind of works on production fails ... we should better figure out now, as otherwise it will bite us in the future.

tedbow’s picture

Status: Needs review » Needs work

Ok, @dawehner, I should have said I didn't have time to look into it yet.

I will.

tedbow’s picture

Ok haven't figured this out yet but the exception that is being trigger comes from drupal_get_filename in bootstrap.inc

// If still unknown, create a user-level error message.
    if (!isset($files[$type][$name])) {
      trigger_error(SafeMarkup::format('The following @type is missing from the file system: @name', array('@type' => $type, '@name' => $name)), E_USER_WARNING);
    }

This problem doesn't show up in GetFilenameUnitTest because it doesn't set the $modules array.

If you add

/**
   * {@inheritdoc}
   */
  public static $modules = array('system');

to the class it gets the same problem.

So the problem is not which containerBuild you add

// Use the testing install profile.
    $container->setParameter('install_profile', 'testing');

to. but rather the problem shows up when you use that line AND the $modules array is NOT empty.

drupal_get_filename get called multiple types with $name == 'testing'
The first time it gets called the $files never gets filled out so this error is triggered.

On subsequent calls $files has been filled out and then this error doesn't happened.

I will take another look tomorrow.

tedbow’s picture

Ok, here is the problem.
In 8.1.x \Drupal\Core\Extension\ExtensionDiscovery::setProfileDirectoriesFromSettings gets called from \Drupal\simpletest\KernelTestBase::enableModules
$module_list = $listing->scan('module');
setProfileDirectoriesFromSettings has
$profile = drupal_get_profile();
In 8.1.x returns null so further down

// In case both profile directories contain the same extension, the actual
    // profile always has precedence.
    if ($profile) {
      $this->profileDirectories[] = drupal_get_path('profile', $profile);
    }

Is skipped

with this patch
$profile = drupal_get_profile();
Returns 'testing.
So that if statement calls
drupal_get_path('profile', $profile);
Which ultimately causes the problem in drupal_get_filenamethat I mentioned in #103

My guess is something needs to be added to \Drupal\simpletest\KernelTestBase::containerBuild to make not through that error but maybe who is more familiar with KernelTestBase and ExtensionDiscovery would have better idea.

tedbow’s picture

Status: Needs work » Needs review

Ok, after chatting with @dawehner about what I found in #103 and #104 I am going to make separate issue to see if we should add

// Use the testing install profile.
    $container->setParameter('install_profile', 'testing');

To \Drupal\simpletest\KernelTestBase::containerBuild

So putting back to Need review for patch in #100

Regarding my comment there

This caused a bunch of tests to fail. Not sure why.

We do know why now explained in #103 and #104

dawehner’s picture

@tedbow
Do you mind opening up the follow up issue, so we don't forget about it?

  1. +++ b/core/includes/bootstrap.inc
    @@ -715,31 +715,19 @@ function drupal_installation_attempted() {
    + *   Use the install_profile container parameter or \Drupal::installProfile()
    + *   instead.
    

    I would just let people not know about \Drupal::installProfile(). Code that needs the installation profile is not really common, so let's just give them good practises

  2. +++ b/core/lib/Drupal/Core/DrupalKernelInterface.php
    @@ -140,4 +140,18 @@ public function preHandle(Request $request);
    +   *
    +   * @throws \Drupal\Core\Installer\Exception\TooManyDistributionsException
    +   *   Thrown when a site has more than one distribution installation profile.
    ...
    +  public function getDistribution();
    

    Here is one question ... is this method useful in the public outside of the context of an installer? Also given the exception it sounds like the method be better just to available in the InstallerKernel. Any thoughts about that?

tedbow’s picture

Here is one question ... is this method useful in the public outside of the context of an installer? Also given the exception it sounds like the method be better just to available in the InstallerKernel. Any thoughts about that?

Yeah it seems to me that this is only useful during install.

So if we moved this to InstallerKernel then we would also have to override getInstallProfile in InstallerKernel because it calls $this->getDistribution().

dawehner’s picture

So if we moved this to InstallerKernel then we would also have to override getInstallProfile in InstallerKernel because it calls $this->getDistribution().

Well, we could keep the getDistribution, but keep it protected by default and just expose it publicly in the installer.

greg.1.anderson’s picture

It seems to me that `DrupalKernel::getDistribution()` is needed outside of the context of the installer. If there is no install profile set in settings.php, then `DrupalKernel::getInstallProfile()` will fall back on `getDistribution()` to determine the installation profile to use. The result of `getInstallProfile()` is exposed by the `install_profile` parameter in the container, which is used by the config installer, the locale module, and potentially other sources. So, moving this behavior into `InstallerKernel::getInstallProfile()` would not work. I believe this is what @dawehner implicitly meant above.

It is easy enough to remove `getDistribution()` from DrupalKernelInterface, and place the public method in InstallerKernel, as suggested. However, `getDistribution()` is called in install.core.inc via `\Drupal::service('kernel')->getDistribution()`. If we removed `getDistribution()` from the interface, then this code would still happen to work, because the 'kernel' service is always an InstallerKernel at this point in the code. I've tried this, it works; I could provide the patch if we wanted to go this way. However, without having `getDistribution()` in the interface, there is no contract that guarantees that this method is available in this service, so this code change is perhaps not desirable.

I talked with @alexpott about this, and his feeling is that `getDistribution()` is similar to `getSitePath()` in terms of usage and requirements, and should therefore be fine to leave in the DrupalKernelInterface.

greg.1.anderson’s picture

Status: Needs review » Reviewed & tested by the community

I tested #100 on Pantheon on a read-only filesystem with a distribution, and it works very well. Pending agreement on #109, I think this is good.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 100: 2156401_100.patch, failed testing.

heddn’s picture

Status: Needs work » Needs review
FileSize
49.75 KB

Re-roll

Status: Needs review » Needs work

The last submitted patch, 112: drupal-avoid_writing-2156401-112.patch, failed testing.

heddn’s picture

Status: Needs work » Needs review
FileSize
51.12 KB
heddn’s picture

Failure using this patch, #2466197: Staging directory should not have to be writeable. and a hacked config_installer (https://gist.github.com/heddn/c8c1f423715fc78880773925d997d630) on platform.

Array to string conversion install.core.inc:2158                        [notice]
Drupal\Core\Installer\Exception\InstallerException: File system:         [error]
Writable (<em>public</em> download method)

Array

Settings file: The <em class="placeholder">Settings file</em> is not
writable.

The Drupal installer requires write permissions to <em
class="placeholder">./sites/default/settings.php</em> during the
installation process. The <a
href="https://www.drupal.org/server-permissions">webhosting
issues</a> documentation section offers help on this and other
topics. in /app/web/core/includes/install.core.inc:2162
Stack trace:
#0 /app/web/core/includes/install.core.inc(1019):
install_display_requirements(Array, Array)
#1 /app/web/core/includes/install.core.inc(653):
install_verify_requirements(Array)
#2 /app/web/core/includes/install.core.inc(531):
install_run_task(Array, Array)
#3 /app/web/core/includes/install.core.inc(116):
install_run_tasks(Array)
#4 /app/vendor/drush/drush/includes/drush.inc(726):
install_drupal(Object(Composer\Autoload\ClassLoader), Array)
#5 /app/vendor/drush/drush/includes/drush.inc(711):
drush_call_user_func_array('install_drupal', Array)
#6 /app/vendor/drush/drush/commands/core/drupal/site_install.inc(80):
drush_op('install_drupal', Object(Composer\Autoload\ClassLoader),
greg.1.anderson’s picture

Is #115 related? This issue avoids writing to settings.php if a distribution provides an installation profile. It does nothing to allow installation to succeed when settings.php is written for some other reason, so I think that the problem above should be addressed in a follow-on issue -- either in #2466197, or some other issue, as appropriate.

heddn’s picture

re #116, I was not sure where to post my test result, so this might be in the wrong location. My local hack is some early work on my part (not ready for public use) for #2723499: drupal_rewrite_settings called in SiteConfigurationForm. May#115 should be directed at it.

dawehner’s picture

I still disagree to add the method to the runtime interface, but well, I don't care that much. You know, its just sometimes helpful to keep the surface area reasonable.

+++ b/core/lib/Drupal/Core/DrupalKernelInterface.php
@@ -138,6 +138,20 @@ public function preHandle(Request $request);
+  /**
+   * Get the name of any discovered profile that is a distribution.
+   *

The documentation doesn't make it clear whether this distribution was actually used during install.

+++ b/core/lib/Drupal/Core/DrupalKernel.php
@@ -1471,6 +1474,42 @@ protected static function setupTrustedHosts(Request $request, $host_patterns) {
+   */
+  public function getDistribution() {
+    $listing = new ExtensionDiscovery($this->root);
+    $listing->setProfileDirectories(array());
+    $info_parser = new InfoParser();

Can we add to the documentation that this actually scans the filesystem or so?

greg.1.anderson’s picture

@dawehner: I care more about getting this patch in than whether or not the method is part of the interface. Talk to @alexpott; I already have a patch that implements #108 if you guys decide that's the way you want to go. I'd just need to reroll it / add it to #114 to put it in -- not hard.

Documentation requests above are reasonable. I'll add that once there's a decision on #108, if someone else doesn't get to it first.

alexpott’s picture

Discussed with @dawehner. Let's go for not exposing the getDistribution() method public on the regular run-time kernel. If we find the need later then we can open another issue to discuss it. However if we make it public now then going backwards is super hard. So let's get the fix that everyone wants and have the API discussions later if necessary.

@greg.1.anderson sorry I should have suggested this approach yesterday - at least you already have the patch :)

greg.1.anderson’s picture

Removing getDistribution() from the interface. Let's see how this fares with the testbot.

Status: Needs review » Needs work

The last submitted patch, 121: 2156401-120.patch, failed testing.

greg.1.anderson’s picture

We need to test getDistribution() when we have an InstallerKernel.

greg.1.anderson’s picture

Version: 8.1.x-dev » 8.2.x-dev
Status: Needs work » Needs review

Update version and run the tests.

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

Thank you a lot! I really like how this is now working. Nothing is really added to the runtime surface

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 123: 2156401-123.patch, failed testing.

greg.1.anderson’s picture

It's a little harder to test this way; getDistribution() must be called on the InstallerKernel, so the test must happen after the kernel is created, but before the installation is completed. I'll get it right eventually...

greg.1.anderson’s picture

Status: Needs work » Needs review
FileSize
47.14 KB

Actually, since the problem is just in the test, I just put the code back the way it was, but used reflection to make the method accessible so that it could be called indirectly in the test.

greg.1.anderson’s picture

FileSize
4.02 KB

Here's the interdiff for 128.

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

This looks great for me!

alexpott’s picture

A few coding standards issues that needed addressing.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 131: 2156401-2-131.patch, failed testing.

dawehner’s picture

Status: Needs work » Reviewed & tested by the community

.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 131: 2156401-2-131.patch, failed testing.

alexpott’s picture

Status: Needs work » Reviewed & tested by the community

Unrelated test fails

heddn’s picture

In a conversation with Greg, it sounded like you need to denote the install profile as a 'distribution'. Should we write some release notes to explain how to make Drupal install as a distribution and fool things so it will install on a RO filesystem? My testing has been with minimal, standard and config_installer. All of which aren't technically distributions.

alexpott’s picture

@heddn It's not just about distributions - it is also if the install profile is already set in the settings.php and the chosen profile matches it - then, with this patch, it will no longer attempt to write it.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 131: 2156401-2-131.patch, failed testing.

The last submitted patch, 131: 2156401-2-131.patch, failed testing.

jonathanshaw’s picture

Patch Failed to apply
error: core/modules/system/src/Tests/Bootstrap/GetFilenameUnitTest.php: No such file or directory

This is different to the unrelated failing migrate test mentioned by @dawehner and @alexpott.

As far as I can see GetFileNameUntiTest has not been touched since May 8, and patch applied fine on May 23.

Does this need a reroll or is the fail still unrelated?

dawehner’s picture

In order to port this to 8.1.x we would ideally

a) keep ConfigInstaller::getInstallationProfile (and call out to some other code)
b) Use underscores for new methdo names in DrupalKernel if possible

alexpott’s picture

Status: Needs work » Needs review
FileSize
46.27 KB

Rerolled - needed to change the GetFilenameTest:: containerBuild() to GetFilenameTest::register() to work in the new phpunit KernelTestBase environment.

claudiu.cristea’s picture

Nits.

  1. +++ b/core/lib/Drupal/Core/DrupalKernel.php
    @@ -1508,4 +1511,61 @@ protected function addServiceFiles(array $service_yamls) {
    +    return $install_profile;
    +
    +  }
    

    Extra empty line.

  2. +++ b/core/lib/Drupal/Core/DrupalKernel.php
    @@ -1508,4 +1511,61 @@ protected function addServiceFiles(array $service_yamls) {
    +   * Scans the filesystem looking for all installation profiles.
    +   * Returns the one that has a 'distribution' entry in its info.yml
    +   * file.  If multiple  profiles are distributions, an exception will
    +   * be thrown.
    +   *
    +   * This is used in two places:
    +   *  1) During installation, if there is a single distribution, then
    +   *     the installer will not write the installation profile name
    +   *     to settings.php.
    +   *  2) Whenever DrupalKernel::getInstallProfile() is called, if there
    +   *     is no installation profile name noted in settings.php, then
    +   *     it will call this function to determine the distribution
    +   *     to use.
    

    The word "Returns" should continue on the first line. Extra space preceding "If multiple". More lines are wrapped too early.

  3. +++ b/core/lib/Drupal/Core/DrupalKernel.php
    @@ -1508,4 +1511,61 @@ protected function addServiceFiles(array $service_yamls) {
    +    $listing->setProfileDirectories(array());
    
    +++ b/core/modules/system/src/Tests/Installer/DistributionProfileExistingSettingsTest.php
    @@ -0,0 +1,160 @@
    +    $this->info = array(
    
    +++ b/core/modules/system/src/Tests/Installer/InstallerExistingSettingsMismatchProfileTest.php
    @@ -39,6 +39,13 @@ protected function setUp() {
    +    $this->settings['settings']['install_profile'] = (object) array(
    
    +++ b/core/modules/system/src/Tests/Installer/MultipleDistributionsProfileTest.php
    @@ -0,0 +1,106 @@
    +      $info = array(
    ...
    +        'distribution' => array(
    ...
    +          'install' => array(
    

    Array short syntax?

balsama’s picture

Updated patch with the nits from #143 addressed.

balsama’s picture

In addition to the passing tests, I can give a +1 to this from my anecdotal in real world testing...

We've been using a backported version of the patch in #142 to install Lightning in an environment with a write protected settings file (and the config_sync/database values in an include file).

dawehner’s picture

  1. +++ b/core/lib/Drupal/Core/Config/ConfigInstaller.php
    @@ -632,20 +640,6 @@ protected function drupalGetPath($type, $name) {
    -  protected function drupalGetProfile() {
    -    // Settings is safe to use because settings.php is written before any module
    -    // is installed.
    -    return Settings::get('install_profile');
    -  }
    

    For less BC break we could return $this->installProfile; That seems to be an easy win.

  2. +++ b/core/modules/system/src/Tests/Installer/InstallerExistingSettingsNoProfileTest.php
    @@ -65,7 +64,7 @@ protected function setUpSettings() {
    -    $this->assertEqual('testing', Settings::get('install_profile'));
    +    $this->assertEqual('testing', \Drupal::installProfile());
    
    +++ b/core/modules/system/src/Tests/Installer/InstallerExistingSettingsTest.php
    @@ -75,6 +76,7 @@ public function testInstaller() {
         $this->assertEqual('testing', drupal_get_profile(), 'Profile was changed from minimal to testing during interactive install.');
    +    $this->assertEqual('testing', Settings::get('install_profile'), 'Profile was correctly changed to testing in Settings.php');
    

    Should we use \Drupal::installProfile() in both places?

  3. +++ b/core/modules/system/src/Tests/Installer/MultipleDistributionsProfileTest.php
    @@ -0,0 +1,106 @@
    +
    +  protected function setUp() {
    ...
    +  /**
    +   * Overrides InstallerTest::setUpLanguage().
    +   */
    ...
    +  /**
    +   * Overrides InstallerTest::setUpProfile().
    +   */
    

    Nitpick: Let's add {@inheritdoc}

phenaproxima’s picture

Fixed all of @dawehner's comments in #146 except for #1, which seems to refer to code that no longer exists.

dawehner’s picture

except for #1, which seems to refer to code that no longer exists.

Exactly that's my point. We are removing a function we don't actually have to remove.

+++ b/core/lib/Drupal/Core/Config/ConfigInstaller.php
@@ -585,7 +593,7 @@ protected function getEnabledExtensions() {
    */
   protected function getProfileStorages($installing_name = '') {
-    $profile = $this->drupalGetProfile();
+    $profile = $this->installProfile;
     $profile_storages = [];
     if ($profile && $profile != $installing_name) {
       $profile_path = $this->drupalGetPath('module', $profile);
@@ -632,20 +640,6 @@ protected function drupalGetPath($type, $name) {

@@ -632,20 +640,6 @@ protected function drupalGetPath($type, $name) {
   }
 
   /**
-   * Gets the install profile from settings.
-   *
-   * @return string|null $profile
-   *   The name of the installation profile or NULL if no installation profile
-   *   is currently active. This is the case for example during the first steps
-   *   of the installer or during unit tests.
-   */
-  protected function drupalGetProfile() {
-    // Settings is safe to use because settings.php is written before any module
-    // is installed.
-    return Settings::get('install_profile');
-  }
-
-  /**
    * Wrapper for drupal_installation_attempted().

This is the code we remove.

dawehner’s picture

I think this patch, in its current form, has a major flaw: ExtensionDiscovery and its call to drupal_get_profile() starts to rely on a working container.
In the case of a working Drupal this is not much of a deal, but in a world of where the cached container is gone, this could become a problem.

In order to solve that problem, here is a possible solution (as discussed with alexpott and mpotter):

  • On install time, write the current profile into core.extension
  • On container build time, get this information into the container from the configuration
  • This allows us to not retrieve the information statically from the container on runtime
  • In case the container goes away, we can still fallback to the container, similar to the way how we fallback to the list of active modules from core.extension

An alternative approach could be to write the installation profile into a services.yml file on install time and then read from that, in case its needed.

dawehner’s picture

Here is a patch on top of addressing the review in #148

Status: Needs review » Needs work

The last submitted patch, 150: 2156401-149.patch, failed testing.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.0-beta1 was released on August 3, 2016, which means new developments and disruptive changes should now be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

alexpott’s picture

Status: Needs work » Needs review
FileSize
2.38 KB
141.04 KB

Fixing #150 and re-rolling.

Status: Needs review » Needs work

The last submitted patch, 153: 2156401-3-153.patch, failed testing.

alexpott’s picture

Status: Needs work » Needs review
FileSize
3.65 KB
48.73 KB

Oopsie... a better patch (against the right branch) and an upgrade path

alexpott’s picture

+++ b/core/lib/Drupal/Core/DrupalKernel.php
@@ -1503,4 +1506,63 @@ protected function addServiceFiles(array $service_yamls) {
+  protected function getDistribution() {

I think if we write the profile to core.extension then we shouldn't add this to the kernel since it just isn't necessary.

Status: Needs review » Needs work

The last submitted patch, 155: 2156401-3-154.patch, failed testing.

alexpott’s picture

Status: Needs work » Needs review
FileSize
1.31 KB
49.59 KB

Interesting...

Status: Needs review » Needs work

The last submitted patch, 158: 2156401-3-158.patch, failed testing.

dawehner’s picture

Status: Needs work » Needs review
FileSize
48.22 KB
1.82 KB

I'm not sure what is going on with the BrowserTestBase failure. While these tests fail for me locally, they still return a proper response.
This fixes the other 2 failing tests.

dawehner’s picture

  1. +++ b/core/includes/install.core.inc
    @@ -2170,13 +2174,34 @@ function install_display_requirements($install_state, $requirements) {
    -  if (Settings::get('install_profile') !== $install_state['parameters']['profile']) {
    +  $settings_value = Settings::get('install_profile');
    +  // We need to write to settings.php if the value in settings.php does not
    +  // equal the selected profile.
    +  $need_to_write = $settings_value !== $install_state['parameters']['profile'];
    +  // However, if we're dealing with a distribution and the profile is not
    +  // writable do not write the value to settings.php if the current value is not
    +  // set.
    +  $distribution = FALSE;
    +  try {
    +    $distribution = \Drupal::service('kernel')->getDistribution();
    +  }
    +  catch (TooManyDistributionsException $e) {
    +    // The user will have chosen.
    +  }
    +
    +  if ($settings_value == '' && $distribution && !is_writable(\Drupal::service('site.path') . '/settings.php')) {
    +    $need_to_write = FALSE;
    +  }
    +
    +  if ($need_to_write) {
         // Remember the profile which was used.
         $settings['settings']['install_profile'] = (object) array(
           'value' => $install_state['parameters']['profile'],
    diff --git a/core/includes/install.inc b/core/includes/install.inc
    

    Shouldn't this function now also write to config, just from an API point of view? The name of the function doesn't point out that its just about settings.php to be honest.

  2. +++ b/core/lib/Drupal/Core/DrupalKernel.php
    @@ -1503,4 +1506,63 @@ protected function addServiceFiles(array $service_yamls) {
    +    $install_profile = Settings::get('install_profile');
    +
    +    if (empty($install_profile) && ($config = $this->getConfigStorage()->read('core.extension')) && isset($config['profile'])) {
    +      $install_profile = $config['profile'];
    +    }
    +    elseif (empty($install_profile)) {
    +      $install_profile = $this->getDistribution();
    +    }
    

    I would try to reorganize this code to make it clear, that Settings::get('install_profile') is just a fallback and the config storage is the primary source of truth.

  3. +++ b/core/modules/system/src/Tests/Installer/DistributionProfileTest.php
    @@ -68,6 +69,10 @@ public function testInstalled() {
    +    // Confirm that Drupal recognizes this distribution as the current profile.
    +    $this->assertEqual(\Drupal::installProfile(), 'mydistro');
    +    $this->assertEqual(Settings::get('install_profile'), 'mydistro', 'The install profile has been written to settings.php.');
    

    IMHO we should check also the config itself

alexpott’s picture

Thanks for the review @dawehner
1. Deprecated in the current patch
2. Completely rewritten
3. Agreed

The current patch goes further and deprecates the install_profile setting. It also removes the getDistribution code because it just is not necessary anymore.

dawehner’s picture

  1. +++ b/core/lib/Drupal.php
    @@ -190,12 +190,13 @@ public static function root() {
        */
       public static function installProfile() {
         if (static::hasContainer()) {
    -      return static::getContainer()->getParameter('install_profile');
    +      $profile = static::getContainer()->getParameter('install_profile');
         }
         else {
           $config_storage = BootstrapConfigStorageFactory::getDatabaseStorage();
    -      return $config_storage->read('core.extension')['profile'];
    +      $profile = $config_storage->read('core.extension')['profile'];
         }
    +    return empty($profile) ? NULL : $profile;
       }
    

    Should we throw an exception here, when there is no profile returned?

  2. +++ b/core/modules/system/src/Tests/Installer/DistributionProfileExistingSettingsTest.php
    @@ -124,44 +122,11 @@ public function testInstalled() {
    -    // Create another installation profile which is a distribution.
    -    $info = [
    -      'type' => 'profile',
    -      'core' => \Drupal::CORE_COMPATIBILITY,
    -      'name' => 'Distribution profile 2',
    -      'distribution' => [
    -        'name' => 'My Distribution 2',
    -        'install' => [
    -          'theme' => 'bartik',
    -        ],
    -      ],
    -    ];
    -    // File API functions are not available yet.
    -    $path = $this->siteDirectory . '/profiles/mydistro2';
    -    mkdir($path, 0777, TRUE);
    -    file_put_contents("$path/mydistro2.info.yml", Yaml::encode($info));
    ...
    +    $this->assertEqual(\Drupal::installProfile(), 'mydistro');
    

    Don't we still want to write the second distribution to test that the first one is taken into account?

  3. +++ b/sites/default/default.settings.php
    @@ -270,6 +270,11 @@
    + *   install profile is written to the core.extension confoguration. If a
    

    I believe confoguration should be confogoroton.

alexpott’s picture

Here's an upgrade path test. I think we need to be cautious with \Drupal::installProfile() (because it is called by drupal_get_profile()) and ensure it returns the correct profile even if it is called before the update is run.

alexpott’s picture

Thanks for the review @dawhener!

  1. We currently support not having an install profile. KernelTestBase tests for example do not have an install profile. I think it does make sense but only in Drupal 9
  2. This is tested in\Drupal\system\Tests\Installer\MultipleDistributionsProfileTest
  3. Fixed :) confoguration is what happens when config confuses us.

The last submitted patch, 162: 2156401-3-162.patch, failed testing.

The last submitted patch, 164: 2156401-3-163.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 165: 2156401-3-165.patch, failed testing.

The last submitted patch, 162: 2156401-3-162.patch, failed testing.

alexpott’s picture

Status: Needs work » Needs review
FileSize
6.14 KB
53.99 KB

Fixing what happens when there is a profile mismatch - ie when a user chooses a choice different to what is written in settings.php and settings.php can not be written.

Crell’s picture

+++ b/core/lib/Drupal.php
@@ -182,6 +184,28 @@ public static function root() {
   /**
+   * Gets the active install profile.
+   *
+   * @return string|null
+   *   The name of the any active install profile or distribution.
+   */
+  public static function installProfile() {
+    if (static::hasContainer()) {
+      $profile = static::getContainer()->getParameter('install_profile');
+    }
+    else {
+      $config_storage = BootstrapConfigStorageFactory::getDatabaseStorage();
+      $profile = $config_storage->read('core.extension')['profile'];
+    }
+    // A BC layer just in in case this only exists in Settings. Introduced in
+    // Drupal 8.3.x and will be removed before Drupal 9.0.0.
+    if (empty($profile)) {
+      $profile = Settings::get('install_profile');
+    }
+    return empty($profile) ? NULL : $profile;
+  }

This is for-reals logic, which means it should not be on the \Drupal global. That object is supposed to be just a procedural code bridge to accessing the container, not a place to put logic not accessible elsewhere in a better fashion.

What am I supposed to do other than calling this static method to get the profile, like if I'm in an class and therefore should not be calling \Drupal, ever?

dawehner’s picture

IMHO all contrib/custom code should use the container parameter to inject this information. Everything else are just internal storage details.

dawehner’s picture

The general direction looks great!

  1. +++ b/core/includes/install.core.inc
    @@ -1212,13 +1214,22 @@ function _install_select_profile(&$install_state) {
    +  // Check for a distribution. If the site has more than one distribution force
    +  // the user to choose.
    +  $listing = new ExtensionDiscovery(\Drupal::root());
    +  $listing->setProfileDirectories([]);
    +  $info_parser = new InfoParser();
    +  $distributions = [];
    +  foreach ($listing->scan('profile') as $profile) {
    +    $info = $info_parser->parse($profile->getPathname());
    +    if (!empty($info['distribution'])) {
    +      $distributions[] = $profile->getName();
         }
       }
    +  // If there is only one distribution then use it.
    +  if (count($distributions) === 1) {
    +    return reset($distributions);
    +  }
    

    From a pure code readability POV I would but that into a helper method like _install_get_all_distributions(), but this is of course a style question.

  2. +++ b/core/includes/install.inc
    @@ -334,7 +334,7 @@ function drupal_rewrite_settings($settings = array(), $settings_file = NULL) {
    -    if (file_put_contents($settings_file, $buffer) === FALSE) {
    +    if (@file_put_contents($settings_file, $buffer) === FALSE) {
    

    Can't we check is_writable instead?

  3. +++ b/core/includes/install.inc
    @@ -621,6 +621,12 @@ function drupal_install_system($install_state) {
    +  // Ensure to also store the installation profile in configuration for later
    +  // use.
    

    The comment could be a little bit misleading. Its not stressing out that the configuration is the primary profile storage

  4. +++ b/core/lib/Drupal.php
    @@ -182,6 +184,28 @@ public static function root() {
       /**
    +   * Gets the active install profile.
    +   *
    +   * @return string|null
    +   *   The name of the any active install profile or distribution.
    +   */
    +  public static function installProfile() {
    

    IMHO this method should describe that you, as runtime level code, better want to inject the install_profile from the container parameters and that's it.

  5. +++ b/core/lib/Drupal/Core/Installer/InstallerKernel.php
    @@ -46,4 +46,24 @@ public function getConfigStorage() {
    diff --git a/core/modules/block/src/Tests/BlockUiTest.php b/core/modules/block/src/Tests/BlockUiTest.php
    
    diff --git a/core/modules/block/src/Tests/BlockUiTest.php b/core/modules/block/src/Tests/BlockUiTest.php
    index f2bcaae..35c3b5f 100644
    
    index f2bcaae..35c3b5f 100644
    --- a/core/modules/block/src/Tests/BlockUiTest.php
    
    --- a/core/modules/block/src/Tests/BlockUiTest.php
    +++ b/core/modules/block/src/Tests/BlockUiTest.php
    
    +++ b/core/modules/block/src/Tests/BlockUiTest.php
    +++ b/core/modules/block/src/Tests/BlockUiTest.php
    @@ -230,7 +230,7 @@ public function testContextAwareBlocks() {
    
    @@ -230,7 +230,7 @@ public function testContextAwareBlocks() {
         $this->assertTrue(!empty($definition), 'The context-aware test block exists.');
         $edit = [
           'region' => 'content',
    -      'settings[context_mapping][user]' => '@block_test.multiple_static_context:userB',
    +      'settings[context_mapping][user]' => '@block_test.multiple_static_context:user2',
         ];
         $this->drupalPostForm($block_url, $edit, 'Save block');
     
    diff --git a/core/modules/block/tests/modules/block_test/src/ContextProvider/MultipleStaticContext.php b/core/modules/block/tests/modules/block_test/src/ContextProvider/MultipleStaticContext.php
    
    diff --git a/core/modules/block/tests/modules/block_test/src/ContextProvider/MultipleStaticContext.php b/core/modules/block/tests/modules/block_test/src/ContextProvider/MultipleStaticContext.php
    index 9ca8132..58a262d 100644
    
    index 9ca8132..58a262d 100644
    --- a/core/modules/block/tests/modules/block_test/src/ContextProvider/MultipleStaticContext.php
    
    --- a/core/modules/block/tests/modules/block_test/src/ContextProvider/MultipleStaticContext.php
    +++ b/core/modules/block/tests/modules/block_test/src/ContextProvider/MultipleStaticContext.php
    
    +++ b/core/modules/block/tests/modules/block_test/src/ContextProvider/MultipleStaticContext.php
    +++ b/core/modules/block/tests/modules/block_test/src/ContextProvider/MultipleStaticContext.php
    @@ -47,9 +47,9 @@ public function __construct(AccountInterface $account, EntityManagerInterface $e
    
    @@ -47,9 +47,9 @@ public function __construct(AccountInterface $account, EntityManagerInterface $e
       public function getRuntimeContexts(array $unqualified_context_ids) {
         $current_user = $this->userStorage->load($this->account->id());
     
    -    $context1 = new Context(new ContextDefinition('entity:user', 'User A'), $current_user);
    +    $context1 = new Context(new ContextDefinition('entity:user', 'User 1'), $current_user);
     
    -    $context2 = new Context(new ContextDefinition('entity:user', 'User B'), $current_user);
    +    $context2 = new Context(new ContextDefinition('entity:user', 'User 2'), $current_user);
     
         $cacheability = new CacheableMetadata();
         $cacheability->setCacheContexts(['user']);
    @@ -58,8 +58,8 @@ public function getRuntimeContexts(array $unqualified_context_ids) {
    
    @@ -58,8 +58,8 @@ public function getRuntimeContexts(array $unqualified_context_ids) {
         $context2->addCacheableDependency($cacheability);
     
         return [
    -      'userA' => $context1,
    -      'userB' => $context2,
    +      'user1' => $context1,
    +      'user2' => $context2,
         ];
       }
     
    

    Does @alexpott creates diff against other versions?

Mile23’s picture

Status: Needs review » Needs work
+++ b/core/lib/Drupal.php
@@ -182,6 +184,28 @@ public static function root() {
+  public static function installProfile() {
...
+    // A BC layer just in in case this only exists in Settings. Introduced in
+    // Drupal 8.3.x and will be removed before Drupal 9.0.0.

+1 on #171. Turn the install_profile parameter into a parameter factory similar to how we did app.root. Then the BC layer can be a separate protected method which can be individually marked as @deprecated.

alexpott’s picture

Status: Needs work » Needs review
FileSize
5.97 KB
51.62 KB
+++ b/core/includes/bootstrap.inc
@@ -716,31 +715,19 @@ function drupal_installation_attempted() {
-  global $install_state;
-
-  if (drupal_installation_attempted()) {
-    // If the profile has been selected return it.
-    if (isset($install_state['parameters']['profile'])) {
-      $profile = $install_state['parameters']['profile'];
-    }
-    else {
-      $profile = NULL;
-    }
-  }
-  else {
-    // Fall back to NULL, if there is no 'install_profile' setting.
-    $profile = Settings::get('install_profile');
-  }

This is a BC change we shouldn't make - could break distributions or things that have changed the installer.

I think all the BC should be in drupal_get_profile - since that is what we are deprecating. Let's see if we were using any of it.

Still need to address some of #173.

alexpott’s picture

Re #173
1. I'd rather not add new methods to the installer tbh.
2. Let's see if that is even needed. If it is imo suppression is a valid option.
3. Fixed
4. in #175 it now just returns the container param.
5. Fixed in #175

alexpott’s picture

Hmm got the BC layer wrong a bit.

The last submitted patch, 175: 2156401-3-175.patch, failed testing.

The last submitted patch, 176: 2156401-3-176.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 177: 2156401-3-177.patch, failed testing.

alexpott’s picture

Status: Needs work » Needs review
dawehner’s picture

1. I'd rather not add new methods to the installer tbh.

Well, an additional private method always improves readability, IMHO, and help to do things properly in the future.

  1. +++ b/core/lib/Drupal/Core/DrupalKernel.php
    @@ -1503,4 +1504,23 @@ protected function addServiceFiles(array $service_yamls) {
    +    // Ensure empty strings are NULLs.
    +    $install_profile = empty($config['profile']) ? NULL : $config['profile'];
    +
    +    // If system_update_8300() has not yet run fallback to using settings.
    +    if (empty($install_profile)) {
    +      $install_profile = Settings::get('install_profile');
    +    }
    

    It is a bit weird to have twice the same condition. What about using if (empty($config['profile']) { $install_profile = Settings::get(...);} else {$install_profile = $config['profile']; } or use the ternary from above

  2. +++ b/core/modules/simpletest/src/KernelTestBase.php
    @@ -231,7 +231,7 @@ protected function setUp() {
    diff --git a/core/modules/simpletest/src/Tests/KernelTestBaseTest.php b/core/modules/simpletest/src/Tests/KernelTestBaseTest.php
    
    diff --git a/core/modules/simpletest/src/Tests/KernelTestBaseTest.php b/core/modules/simpletest/src/Tests/KernelTestBaseTest.php
    index 15ecf1f..5876eb7 100644
    
    index 15ecf1f..5876eb7 100644
    --- a/core/modules/simpletest/src/Tests/KernelTestBaseTest.php
    
    --- a/core/modules/simpletest/src/Tests/KernelTestBaseTest.php
    +++ b/core/modules/simpletest/src/Tests/KernelTestBaseTest.php
    
    +++ b/core/modules/simpletest/src/Tests/KernelTestBaseTest.php
    +++ b/core/modules/simpletest/src/Tests/KernelTestBaseTest.php
    @@ -323,13 +323,13 @@ function testNoThemeByDefault() {
    
    @@ -323,13 +323,13 @@ function testNoThemeByDefault() {
       }
     
       /**
    -   * Tests that drupal_get_profile() returns NULL.
    +   * Tests that \Drupal::installProfile() returns FALSE.
        *
        * As the currently active installation profile is used when installing
        * configuration, for example, this is essential to ensure test isolation.
        */
       public function testDrupalGetProfile() {
    -    $this->assertNull(drupal_get_profile());
    +    $this->assertFalse(\Drupal::installProfile());
       }
     
       /**
    

    Should we use assertIdentical('', instead?

alexpott’s picture

Actually the whole choose a distribution when there is more than one change is not necessary anymore. I could have removed core/modules/system/src/Tests/Installer/MultipleDistributionsProfileTest.php since this functionality is no longer changed by the test but I feel since it is an installer test and this code is untested atm it is better to leave this test in and change it to test the HEAD behaviour.

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

Great idea.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 183: 2156401-3-183.patch, failed testing.

dawehner’s picture

Status: Needs work » Reviewed & tested by the community

The patch is still green ...

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 183: 2156401-3-183.patch, failed testing.

alexpott’s picture

Status: Needs work » Reviewed & tested by the community
FileSize
50.26 KB

Conflict in system.install because another hook_update_N function added...

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 188: 2156401-3-188.patch, failed testing.

The last submitted patch, 188: 2156401-3-188.patch, failed testing.

daffie’s picture

Status: Needs work » Reviewed & tested by the community

Back to RTBC.

alexpott’s picture

Title: Avoid writing install_profile value to settings.php when provided by a Distribution » Write install_profile value to configuration and only to settings.php if it is writeable

A more honest title.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 188: 2156401-3-188.patch, failed testing.

The last submitted patch, 188: 2156401-3-188.patch, failed testing.

daffie’s picture

Issue tags: +Needs reroll
Manuel Garcia’s picture

Status: Needs work » Needs review
Issue tags: -Needs reroll
FileSize
50.07 KB

Rerolled #188 - just a simple conflict on system.install

alexpott’s picture

Status: Needs review » Reviewed & tested by the community
21c21
< index 6310c21..4872750 100644
---
> index d1223e9..0fba9f6 100644
43c43
< index ec12097..170d532 100644
---
> index 71895b2..5d451f4 100644
46c46
< @@ -8,6 +8,7 @@
---
> @@ -9,6 +9,7 @@
54c54
< @@ -716,12 +717,20 @@ function drupal_installation_attempted() {
---
> @@ -724,12 +725,20 @@ function drupal_installation_attempted() {
76c76
< @@ -736,8 +745,18 @@ function drupal_get_profile() {
---
> @@ -744,8 +753,18 @@ function drupal_get_profile() {
161c161
< index f62e914..81c9190 100644
---
> index bc21709..b4b6cf5 100644
182c182
< index 97c3688..2ce0591 100644
---
> index f98691f..4608055 100644
257c257
< @@ -644,9 +653,7 @@ protected function drupalGetPath($type, $name) {
---
> @@ -671,9 +680,7 @@ protected function drupalGetPath($type, $name) {
358c358
< index 3ccb2d7..99f00d2 100644
---
> index ab2f645..3f4fd06 100644
361c361
< @@ -1153,6 +1153,7 @@ protected function compileContainer() {
---
> @@ -1161,6 +1161,7 @@ protected function compileContainer() {
369c369
< @@ -1503,4 +1504,24 @@ protected function addServiceFiles(array $service_yamls) {
---
> @@ -1511,4 +1512,24 @@ protected function addServiceFiles(array $service_yamls) {
1115c1115
< index 1781105..8efea11 100644
---
> index 3ef24a5..7c8a9aa 100644
1118,1121c1118,1121
< @@ -1680,3 +1680,21 @@ function system_update_8200(&$sandbox) {
<    $sandbox['config_names'] = array_diff($sandbox['config_names'], $config_names_to_process);
<    $sandbox['#finished'] = empty($sandbox['config_names']) ? 1 : ($sandbox['max'] - count($sandbox['config_names'])) / $sandbox['max'];
<  }
---
> @@ -1730,3 +1730,21 @@ function system_update_8201() {
>  /**
>   * @} End of "addtogroup updates-8.2.0".
>   */
1216c1216
< index 0146607..447cb76 100644
---
> index c34e45f..552a952 100644
1219c1219
< @@ -398,6 +398,7 @@ private function bootKernel() {
---
> @@ -391,6 +391,7 @@ private function bootKernel() {

The diff between #188 and #196 looks great.

catch’s picture

Status: Reviewed & tested by the community » Needs review

In general I think we should be moving away from install profiles being active on installed sites, however that's not the case at all in 8.x, so improving how it works now is fine.

  1. +++ b/core/lib/Drupal/Core/DrupalKernel.php
    @@ -1511,4 +1512,24 @@ protected function addServiceFiles(array $service_yamls) {
    +    else {
    +      // If system_update_8300() has not yet run fallback to using settings.
    +      $install_profile = Settings::get('install_profile');
    +    }
    

    This could have a @todo to remove, and we could probably get rid of it in 8.4.x

  2. +++ b/core/lib/Drupal/Core/EventSubscriber/ConfigImportSubscriber.php
    @@ -129,10 +129,15 @@ protected function validateModules(ConfigImporter $config_importer) {
    +
    +    // Ensure the profile is not changing.
    +    if ($install_profile !== $core_extension['profile']) {
    +      $config_importer->logError($this->t('Cannot change the install profile from %new_profile to %profile once Drupal is installed.', array('%profile' => $install_profile, '%new_profile' => $core_extension['profile'])));
    +    }
       }
    

    So on the one hand it's good to enforce this.

    On the other, what happens if an install profile is marked unsupported during 8.x's release? Or if you for some other reason want to migrate off it? It's currently theoretically possible to hack that via changing settings.php, this looks like it'd make it harder.

dawehner’s picture

On the other, what happens if an install profile is marked unsupported during 8.x's release? Or if you for some other reason want to migrate off it? It's currently theoretically possible to hack that via changing settings.php, this looks like it'd make it harder.

Well, one could still do a runtime level override using global $conf.

dawehner’s picture

This could have a @todo to remove, and we could probably get rid of it in 8.4.x

Well, couldn't this break existing sites at any point in time?

catch’s picture

If that's true, then the comment is wrong:

 // If system_update_8300() has not yet run fallback to using settings.
alexpott’s picture

I agree we should have an @todo to remove this code however given this is called before updates have run I think we can't remove till 9.x because it should be possible to update from 8.1.x to 8.4.x without having to have the 8.3.x codebase. Say you forgot to update a site for whatever reason. Opened #2831065: Remove BC layer from \Drupal\Core\DrupalKernel::getInstallProfile() against 9.x.

Re #198.2 is it already impossible to change the install profile because we validate you are not uninstalling it :) because they are still modules. This check is just checking that the module list and the new configuration don't get out of sync.

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

Thank you alex for adding the follow up!

  • catch committed 480eb82 on 8.3.x
    Issue #2156401 by alexpott, moshe weitzman, tedbow, dawehner, greg.1....
catch’s picture

Status: Reviewed & tested by the community » Fixed

Alright I was concerned this makes it impossible to change the profile - while we don't support that, we also don't offer any way for people to migrate off unsupported (in the d.o sense) profiles so it can be necessary to do that for disaster recovery. It doesn't make it impossible, it does make it a bit harder but @alexpott's updated the change record with an example of how to do it.

So committed/pushed to 8.3.x, thanks!

jhodgdon’s picture

Status: Fixed » Needs work

This commit broke my contrib module, by adding a new argument to the constructor for core/lib/Drupal/Core/Config/ExtensionInstallStorage.php

Isn't this an API change? I cannot make a version of my module that is compatible with both Drupal 8.2.x and 8.3.x because of this change. I have a service that depends on this class and I have to supply arguments to the constructor... Can you please revert this?

jhodgdon’s picture

Here's the test that broke from this commit...
https://www.drupal.org/pift-ci-job/541244

  • catch committed ef809cb on 8.3.x
    Revert "Issue #2156401 by alexpott, moshe weitzman, tedbow, dawehner,...
catch’s picture

Reverted.

In other patches we've made the parameter optional with a \Drupal fallback, we can do that here too.

alexpott’s picture

Status: Needs work » Needs review
FileSize
6.16 KB
50.27 KB

@jhodgdon thanks for the quick feedback - we should definitely not break an API for this change.

The shame of course is that we can't make the code future proof because of the mix of optional and required params but at least we can trigger a silent deprecation notice and in Drupal 9 consider removing all optional params since of code that complies with the deprecation notice will be passing in all of the parameters.

Drupal test run
---------------

Tests to be run:
  - \Drupal\config_update_ui\Tests\ConfigUpdateTest

Test run started:
  Wednesday, November 30, 2016 - 12:46

Test summary
------------

\Drupal\config_update_ui\Tests\ConfigUpdateTest              358 passes

Test run duration: 9 sec

Test result from your module with this patch applied.

jhodgdon’s picture

Thanks for the quick action!

Can't a new parameter be added at the end of the parameter list, with a default? Then my module wouldn't break, at least I think so... Ah, that's what you did.

I'll review the interdiff... Looks good except for maybe this:

+++ b/core/lib/Drupal/Core/Config/ExtensionInstallStorage.php
@@ -50,13 +48,17 @@ class ExtensionInstallStorage extends InstallStorage {
+   * @param string $profile
+   *   The current installation profile.

Should this be marked (optional)? It does have a default... kind of... Maybe a note should be added that the parameter is technically optional in D8 but will become required in D9, or something like that? Or a deprecation notice that not supplying the parameter is deprecated in D8?

  • catch committed 480eb82 on 8.4.x
    Issue #2156401 by alexpott, moshe weitzman, tedbow, dawehner, greg.1....
  • catch committed ef809cb on 8.4.x
    Revert "Issue #2156401 by alexpott, moshe weitzman, tedbow, dawehner,...

  • catch committed 480eb82 on 8.4.x
    Issue #2156401 by alexpott, moshe weitzman, tedbow, dawehner, greg.1....
  • catch committed ef809cb on 8.4.x
    Revert "Issue #2156401 by alexpott, moshe weitzman, tedbow, dawehner,...

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.0-alpha1 will be released the week of January 30, 2017, which means new developments and disruptive changes should now be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

dawehner’s picture

Issue tags: +Novice

The remaining task seems to be a novice issue.

alexpott’s picture

Here's the docs update.

The interdiff is a bit of lie - there is also a change to system_install() to update the hook_update_N number to 8301.

dawehner’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: -Novice

This looks good to go for me.

+++ b/core/lib/Drupal/Core/Config/ExtensionInstallStorage.php
@@ -42,11 +48,19 @@ class ExtensionInstallStorage extends InstallStorage {
+    if (is_null($profile)) {
+      @trigger_error('Install profile will be a mandatory parameter in Drupal 9.0.', E_USER_DEPRECATED);
+    }

<3

  • catch committed ebe2d76 on 8.4.x
    Issue #2156401 by alexpott, moshe weitzman, tedbow, dawehner, greg.1....

  • catch committed 40f803a on 8.3.x
    Issue #2156401 by alexpott, moshe weitzman, tedbow, dawehner, greg.1....
catch’s picture

Status: Reviewed & tested by the community » Fixed

Committed/pushed to 8.4.x and cherry-picked to 8.3.x. Thanks!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.