diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index 44ff142..854f1dd 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -205,6 +205,8 @@ function install_state_defaults() { 'profile_info' => array(), // An array of available installation profiles. 'profiles' => array(), + // The name of the theme to use during installation. + 'theme' => 'seven', // The server URL where the interface translation files can be downloaded. // Tokens in the pattern will be replaced by appropriate values for the // required translation file. @@ -377,17 +379,6 @@ function install_begin_request(&$install_state) { \Drupal::translation()->setDefaultLangcode($install_state['parameters']['langcode']); } - $module_handler = \Drupal::moduleHandler(); - if (!$module_handler->moduleExists('system')) { - // Override the module list with a minimal set of modules. - $module_handler->setModuleList(array('system' => 'core/modules/system/system.module')); - } - // After setting up a custom and finite module list in a custom low-level - // bootstrap like here, ensure to use ModuleHandler::loadAll() so that - // ModuleHandler::isLoaded() returns TRUE, since that is a condition being - // checked by other subsystems (e.g., the theme system). - $module_handler->loadAll(); - // Add list of all available profiles to the installation state. $listing = new ExtensionDiscovery(); $listing->setProfileDirectories(array()); @@ -398,6 +389,30 @@ function install_begin_request(&$install_state) { drupal_get_filename('profile', $name, $profile->uri); } + if ($profile = _install_select_profile($install_state)) { + $install_state['parameters']['profile'] = $profile; + install_load_profile($install_state); + if (isset($install_state['profile_info']['distribution']['install']['theme'])) { + $install_state['theme'] = $install_state['profile_info']['distribution']['install']['theme']; + } + } + + // Override the module list with a minimal set of modules. + $module_handler = \Drupal::moduleHandler(); + $module_list = $module_handler->getModuleList(); + if (!$module_handler->moduleExists('system')) { + $module_list['system'] = 'core/modules/system/system.module'; + } + if ($profile && !$module_handler->moduleExists($profile)) { + $module_list[$profile] = $install_state['profiles'][$profile]->uri; + } + $module_handler->setModuleList($module_list); + // After setting up a custom and finite module list in a custom low-level + // bootstrap like here, ensure to use ModuleHandler::loadAll() so that + // ModuleHandler::isLoaded() returns TRUE, since that is a condition being + // checked by other subsystems (e.g., the theme system). + $module_handler->loadAll(); + // Prepare for themed output. We need to run this at the beginning of the // page request to avoid a different theme accidentally getting set. (We also // need to run it even in the case of command-line installations, to prevent @@ -639,7 +654,7 @@ function install_tasks($install_state) { ), 'install_select_profile' => array( 'display_name' => t('Choose profile'), - 'display' => count($install_state['profiles']) != 1, + 'display' => empty($install_state['profile_info']['distribution']['name']) && count($install_state['profiles']) != 1, 'run' => INSTALL_TASK_RUN_IF_REACHED, ), 'install_load_profile' => array( @@ -664,7 +679,7 @@ function install_tasks($install_state) { 'run' => INSTALL_TASK_RUN_IF_REACHED, ), 'install_profile_modules' => array( - 'display_name' => count($install_state['profiles']) == 1 ? t('Install site') : t('Installation profile'), + 'display_name' => t('Install site'), 'type' => 'batch', ), 'install_import_translations' => array( @@ -1220,7 +1235,7 @@ function install_select_profile(&$install_state) { throw new NoProfilesException(\Drupal::service('string_translation')); } // Try to automatically select a profile. - if ($profile = _install_select_profile($install_state['profiles'])) { + if ($profile = _install_select_profile($install_state)) { $install_state['parameters']['profile'] = $profile; } else { @@ -1235,49 +1250,45 @@ function install_select_profile(&$install_state) { } /** - * Selects an installation profile. + * Determines the installation profile to use in the installer. * - * A profile will be selected if: - * - Only one profile is available, - * - A profile was submitted through \Drupal::request()->request, - * - Exactly one of the profiles is marked as "exclusive". - * If multiple profiles are marked as "exclusive" then no profile will be - * selected. + * A profile will be selected in the following order of conditions: * - * @param array $profiles - * An associative array of profiles with the machine-readable names as keys. + * 1. Only one profile is available. + * 2. A specific profile name is requested in installation parameters: + * - for interactive installations via request query parameters. + * - for non-interactive installations via install_drupal() settings. + * 3. A discovered profile that is a distribution. + * If multiple profiles are distributions, then the first discovered profile + * will be selected. + * + * @param array $install_state + * The current installer state, containing a 'profiles' key, which is an + * associative array of profiles with the machine-readable names as keys. * * @return * The machine-readable name of the selected profile or NULL if no profile was * selected. */ -function _install_select_profile($profiles) { +function _install_select_profile(&$install_state) { // Don't need to choose profile if only one available. - $request_params = \Drupal::request()->request; - if (count($profiles) == 1) { - $profile = array_pop($profiles); + if (count($install_state['profiles']) == 1) { + $profile = reset($install_state['profiles']); return $profile->getName(); } - elseif ($request_params->has('profile') && ($profile = $request_params->get('profile')) && isset($profiles[$profile])) { - return $profiles[$profile]->getName(); + if (!empty($install_state['parameters']['profile'])) { + $profile = $install_state['parameters']['profile']; + if (isset($install_state['profiles'][$profile])) { + return $install_state['profiles'][$profile]->getName(); + } } - // Check for a profile marked as "exclusive" and ensure that only one - // profile is marked as such. - $exclusive_profile = NULL; - foreach ($profiles as $profile) { + // Check for a distribution profile. + foreach ($install_state['profiles'] as $profile) { $profile_info = install_profile_info($profile->getName()); - if (!empty($profile_info['exclusive'])) { - if (empty($exclusive_profile)) { - $exclusive_profile = $profile->getName(); - } - else { - // We found a second "exclusive" profile. There's no way to choose - // between them, so we ignore the property. - return; - } + if (!empty($profile_info['distribution'])) { + return $profile->getName(); } } - return $exclusive_profile; } /** @@ -1352,6 +1363,14 @@ function install_select_profile_form($form, &$form_state, $install_state) { } /** + * Form submission handler for install_select_profile_form(). + */ +function install_select_profile_form_submit($form, &$form_state) { + global $install_state; + $install_state['parameters']['profile'] = $form_state['values']['profile']; +} + +/** * Finds all .po files that are useful to the installer. * * @return @@ -1755,7 +1774,7 @@ function install_load_profile(&$install_state) { $profile_file = $install_state['profiles'][$profile]->uri; if (file_exists($profile_file)) { include_once DRUPAL_ROOT . '/' . $profile_file; - $install_state['profile_info'] = install_profile_info($install_state['parameters']['profile'], $install_state['parameters']['langcode']); + $install_state['profile_info'] = install_profile_info($install_state['parameters']['profile'], isset($install_state['parameters']['langcode']) ? $install_state['parameters']['langcode'] : 'en'); } else { throw new InstallerException(t('Sorry, the profile you have chosen cannot be loaded.')); diff --git a/core/includes/install.inc b/core/includes/install.inc index c2a138c..f8b8daf 100644 --- a/core/includes/install.inc +++ b/core/includes/install.inc @@ -97,13 +97,13 @@ function drupal_install_profile_distribution_name() { // installation state (it might not be saved anywhere yet). if (drupal_installation_attempted()) { global $install_state; - return isset($install_state['profile_info']['distribution_name']) ? $install_state['profile_info']['distribution_name'] : 'Drupal'; + return isset($install_state['profile_info']['distribution']['name']) ? $install_state['profile_info']['distribution']['name'] : 'Drupal'; } // At all other times, we load the profile via standard methods. else { $profile = drupal_get_profile(); $info = system_get_info('module', $profile); - return $info['distribution_name']; + return $info['distribution']['name']; } } @@ -1046,15 +1046,14 @@ function drupal_check_module($module) { * Additional, less commonly-used information that can appear in a * profile.info.yml file but not in a normal Drupal module .info.yml file * includes: - * - distribution_name: The name of the Drupal distribution that is being - * installed, to be shown throughout the installation process. Defaults to - * 'Drupal'. - * - exclusive: If the install profile is intended to be the only eligible - * choice in a distribution, setting exclusive = TRUE will auto-select it - * during installation, and the install profile selection screen will be - * skipped. If more than one profile is found where exclusive = TRUE then - * this property will have no effect and the profile selection screen will - * be shown as normal with all available profiles shown. + * - distribution: Existence of this key denotes that the install profile is + * intended to be the only eligible choice in a distribution and will be + * auto-selected during installation, whereas the installation profile + * selection screen will be skipped. If more than one distribution profile is + * found then the first discovered one will be selected. + * The following subproperties may be set: + * - name: The name of the Drupal distribution that is being installed, to be + * shown throughout the installation process. Defaults to 'Drupal'. * * Note that this function does an expensive file system scan to get info file * information for dependencies. If you only need information from the info @@ -1084,7 +1083,6 @@ function install_profile_info($profile, $langcode = 'en') { $defaults = array( 'dependencies' => array(), 'description' => '', - 'distribution_name' => 'Drupal', 'version' => NULL, 'hidden' => FALSE, 'php' => DRUPAL_MINIMUM_PHP, diff --git a/core/includes/theme.inc b/core/includes/theme.inc index a58b59a..e46e0af 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -2436,7 +2436,11 @@ function template_preprocess_install_page(&$variables) { $variables['attributes']['class'][] = 'install-page'; // Override the site name that is displayed on the page, since Drupal is // still in the process of being installed. - $variables['site_name'] = drupal_install_profile_distribution_name(); + $distribution_name = String::checkPlain(drupal_install_profile_distribution_name()); + $variables['site_name'] = $distribution_name; + $variables['head_title_array']['name'] = $distribution_name; + + $variables['head_title'] = implode(' | ', $variables['head_title_array']); } /** diff --git a/core/includes/theme.maintenance.inc b/core/includes/theme.maintenance.inc index 21c8d07..429b932 100644 --- a/core/includes/theme.maintenance.inc +++ b/core/includes/theme.maintenance.inc @@ -34,7 +34,12 @@ function _drupal_maintenance_theme() { // Install and update pages are treated differently to prevent theming overrides. if (defined('MAINTENANCE_MODE') && (MAINTENANCE_MODE == 'install' || MAINTENANCE_MODE == 'update')) { - $custom_theme = settings()->get('maintenance_theme', 'seven'); + if (drupal_installation_attempted()) { + $custom_theme = $GLOBALS['install_state']['theme']; + } + else { + $custom_theme = settings()->get('maintenance_theme', 'seven'); + } } else { // The bootstrap was not complete. So we are operating in a crippled diff --git a/core/modules/system/lib/Drupal/system/Tests/Installer/DistributionProfileTest.php b/core/modules/system/lib/Drupal/system/Tests/Installer/DistributionProfileTest.php new file mode 100644 index 0000000..4e3ae04 --- /dev/null +++ b/core/modules/system/lib/Drupal/system/Tests/Installer/DistributionProfileTest.php @@ -0,0 +1,85 @@ + 'Distribution installation profile test', + 'description' => 'Tests distribution profile support.', + 'group' => 'Installer', + ); + } + + protected function setUp() { + $this->info = array( + 'type' => 'profile', + 'core' => \Drupal::CORE_COMPATIBILITY, + 'name' => 'Distribution profile', + 'distribution' => array( + 'name' => 'My Distribution', + 'install' => array( + 'theme' => 'bartik', + ), + ), + ); + // File API functions are not available yet. + $path = $this->siteDirectory . '/profiles/mydistro'; + mkdir($path, 0777, TRUE); + file_put_contents("$path/mydistro.info.yml", Yaml::dump($this->info, PHP_INT_MAX, 2)); + file_put_contents("$path/mydistro.profile", "assertRaw($this->info['distribution']['name']); + // Verify that the requested theme is used. + $this->assertRaw($this->info['distribution']['install']['theme']); + // Verify that the "Choose profile" step does not appear. + $this->assertNoText('profile'); + + parent::setUpLanguage(); + } + + /** + * Overrides InstallerTest::setUpProfile(). + */ + protected function setUpProfile() { + // This step is skipped, because there is a distribution profile. + } + + /** + * Confirms that the installation succeeded. + */ + public function testInstalled() { + $this->assertUrl('user/1'); + $this->assertResponse(200); + // Confirm that we are logged-in after installation. + $this->assertText($this->root_user->getUsername()); + } + +} diff --git a/core/modules/system/system.module b/core/modules/system/system.module index 721bcf8..3b80119 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -1414,8 +1414,8 @@ function _system_rebuild_module_data() { $modules[$profile]->info['required'] = TRUE; // Add a default distribution name if the profile did not provide one. This // matches the default value used in install_profile_info(). - if (!isset($modules[$profile]->info['distribution_name'])) { - $modules[$profile]->info['distribution_name'] = 'Drupal'; + if (!isset($modules[$profile]->info['distribution']['name'])) { + $modules[$profile]->info['distribution']['name'] = 'Drupal'; } }