comparison core/includes/install.inc @ 4:a9cd425dd02b

Update, including to Drupal core 8.6.10
author Chris Cannam
date Thu, 28 Feb 2019 13:11:55 +0000
parents c75dbcec494b
children 12f9dff5fda9
comparison
equal deleted inserted replaced
3:307d7a7fd348 4:a9cd425dd02b
9 use Symfony\Component\HttpFoundation\RedirectResponse; 9 use Symfony\Component\HttpFoundation\RedirectResponse;
10 use Drupal\Component\Utility\Crypt; 10 use Drupal\Component\Utility\Crypt;
11 use Drupal\Component\Utility\OpCodeCache; 11 use Drupal\Component\Utility\OpCodeCache;
12 use Drupal\Component\Utility\UrlHelper; 12 use Drupal\Component\Utility\UrlHelper;
13 use Drupal\Core\Extension\ExtensionDiscovery; 13 use Drupal\Core\Extension\ExtensionDiscovery;
14 use Drupal\Core\Extension\ModuleHandler;
14 use Drupal\Core\Site\Settings; 15 use Drupal\Core\Site\Settings;
15 16
16 /** 17 /**
17 * Requirement severity -- Informational message only. 18 * Requirement severity -- Informational message only.
18 */ 19 */
378 $is_string = $type == T_CONSTANT_ENCAPSED_STRING; 379 $is_string = $type == T_CONSTANT_ENCAPSED_STRING;
379 $is_boolean_or_null = $type == T_STRING && in_array(strtoupper($value), ['TRUE', 'FALSE', 'NULL']); 380 $is_boolean_or_null = $type == T_STRING && in_array(strtoupper($value), ['TRUE', 'FALSE', 'NULL']);
380 return $is_integer || $is_float || $is_string || $is_boolean_or_null; 381 return $is_integer || $is_float || $is_string || $is_boolean_or_null;
381 } 382 }
382 383
383
384 /** 384 /**
385 * Helper for drupal_rewrite_settings(). 385 * Helper for drupal_rewrite_settings().
386 * 386 *
387 * Checks whether this token represents a valid array index: a number or a 387 * Checks whether this token represents a valid array index: a number or a
388 * string. 388 * string.
448 $return .= _drupal_rewrite_settings_dump($v, $variable_name . "['" . $k . "']"); 448 $return .= _drupal_rewrite_settings_dump($v, $variable_name . "['" . $k . "']");
449 } 449 }
450 } 450 }
451 return $return; 451 return $return;
452 } 452 }
453
454 453
455 /** 454 /**
456 * Helper for drupal_rewrite_settings(). 455 * Helper for drupal_rewrite_settings().
457 * 456 *
458 * Dump the value of a value property and adds the comment if it exists. 457 * Dump the value of a value property and adds the comment if it exists.
481 * 480 *
482 * @see install_settings_form_submit() 481 * @see install_settings_form_submit()
483 * @see update_prepare_d8_bootstrap() 482 * @see update_prepare_d8_bootstrap()
484 */ 483 */
485 function drupal_install_config_directories() { 484 function drupal_install_config_directories() {
486 global $config_directories; 485 global $config_directories, $install_state;
487 486
488 // Add a randomized config directory name to settings.php, unless it was 487 // If settings.php does not contain a config sync directory name we need to
489 // manually defined in the existing already. 488 // configure one.
490 if (empty($config_directories[CONFIG_SYNC_DIRECTORY])) { 489 if (empty($config_directories[CONFIG_SYNC_DIRECTORY])) {
491 $config_directories[CONFIG_SYNC_DIRECTORY] = \Drupal::service('site.path') . '/files/config_' . Crypt::randomBytesBase64(55) . '/sync'; 490 if (empty($install_state['config_install_path'])) {
491 // Add a randomized config directory name to settings.php
492 $config_directories[CONFIG_SYNC_DIRECTORY] = \Drupal::service('site.path') . '/files/config_' . Crypt::randomBytesBase64(55) . '/sync';
493 }
494 else {
495 // Install profiles can contain a config sync directory. If they do,
496 // 'config_install_path' is a path to the directory.
497 $config_directories[CONFIG_SYNC_DIRECTORY] = $install_state['config_install_path'];
498 }
492 $settings['config_directories'][CONFIG_SYNC_DIRECTORY] = (object) [ 499 $settings['config_directories'][CONFIG_SYNC_DIRECTORY] = (object) [
493 'value' => $config_directories[CONFIG_SYNC_DIRECTORY], 500 'value' => $config_directories[CONFIG_SYNC_DIRECTORY],
494 'required' => TRUE, 501 'required' => TRUE,
495 ]; 502 ];
496 // Rewrite settings.php, which also sets the value as global variable. 503 // Rewrite settings.php, which also sets the value as global variable.
572 // The installation profile is also a module, which needs to be installed 579 // The installation profile is also a module, which needs to be installed
573 // after all the other dependencies have been installed. 580 // after all the other dependencies have been installed.
574 $present_modules[] = $profile; 581 $present_modules[] = $profile;
575 582
576 // Verify that all of the profile's required modules are present. 583 // Verify that all of the profile's required modules are present.
577 $missing_modules = array_diff($info['dependencies'], $present_modules); 584 $missing_modules = array_diff($info['install'], $present_modules);
578 585
579 $requirements = []; 586 $requirements = [];
580 587
581 if ($missing_modules) { 588 if ($missing_modules) {
582 $build = [ 589 $build = [
610 * to set the default language. 617 * to set the default language.
611 */ 618 */
612 function drupal_install_system($install_state) { 619 function drupal_install_system($install_state) {
613 // Remove the service provider of the early installer. 620 // Remove the service provider of the early installer.
614 unset($GLOBALS['conf']['container_service_providers']['InstallerServiceProvider']); 621 unset($GLOBALS['conf']['container_service_providers']['InstallerServiceProvider']);
622 // Add the normal installer service provider.
623 $GLOBALS['conf']['container_service_providers']['InstallerServiceProvider'] = 'Drupal\Core\Installer\NormalInstallerServiceProvider';
615 624
616 $request = \Drupal::request(); 625 $request = \Drupal::request();
617 // Reboot into a full production environment to continue the installation. 626 // Reboot into a full production environment to continue the installation.
618 /** @var \Drupal\Core\Installer\InstallerKernel $kernel */ 627 /** @var \Drupal\Core\Installer\InstallerKernel $kernel */
619 $kernel = \Drupal::service('kernel'); 628 $kernel = \Drupal::service('kernel');
620 $kernel->shutdown(); 629 $kernel->shutdown();
621 // Have installer rebuild from the disk, rather then building from scratch. 630 // Have installer rebuild from the disk, rather then building from scratch.
622 $kernel->rebuildContainer(FALSE); 631 $kernel->rebuildContainer(FALSE);
623 $kernel->prepareLegacyRequest($request); 632 $kernel->prepareLegacyRequest($request);
624 633
634 // Before having installed the system module and being able to do a module
635 // rebuild, prime the \Drupal\Core\Extension\ModuleExtensionList static cache
636 // with the module's location.
637 // @todo Try to install system as any other module, see
638 // https://www.drupal.org/node/2719315.
639 \Drupal::service('extension.list.module')->setPathname('system', 'core/modules/system/system.info.yml');
640
625 // Install base system configuration. 641 // Install base system configuration.
626 \Drupal::service('config.installer')->installDefaultConfig('core', 'core'); 642 \Drupal::service('config.installer')->installDefaultConfig('core', 'core');
627 643
628 // Store the installation profile in configuration to populate the 644 // Store the installation profile in configuration to populate the
629 // 'install_profile' container parameter. 645 // 'install_profile' container parameter.
651 * The file to check for. 667 * The file to check for.
652 * @param $mask 668 * @param $mask
653 * An optional bitmask created from various FILE_* constants. 669 * An optional bitmask created from various FILE_* constants.
654 * @param $type 670 * @param $type
655 * The type of file. Can be file (default), dir, or link. 671 * The type of file. Can be file (default), dir, or link.
672 * @param bool $autofix
673 * (optional) Determines whether to attempt fixing the permissions according
674 * to the provided $mask. Defaults to TRUE.
656 * 675 *
657 * @return 676 * @return
658 * TRUE on success or FALSE on failure. A message is set for the latter. 677 * TRUE on success or FALSE on failure. A message is set for the latter.
659 */ 678 */
660 function drupal_verify_install_file($file, $mask = NULL, $type = 'file') { 679 function drupal_verify_install_file($file, $mask = NULL, $type = 'file', $autofix = TRUE) {
661 $return = TRUE; 680 $return = TRUE;
662 // Check for files that shouldn't be there. 681 // Check for files that shouldn't be there.
663 if (isset($mask) && ($mask & FILE_NOT_EXIST) && file_exists($file)) { 682 if (isset($mask) && ($mask & FILE_NOT_EXIST) && file_exists($file)) {
664 return FALSE; 683 return FALSE;
665 } 684 }
677 foreach ($masks as $current_mask) { 696 foreach ($masks as $current_mask) {
678 if ($mask & $current_mask) { 697 if ($mask & $current_mask) {
679 switch ($current_mask) { 698 switch ($current_mask) {
680 case FILE_EXIST: 699 case FILE_EXIST:
681 if (!file_exists($file)) { 700 if (!file_exists($file)) {
682 if ($type == 'dir') { 701 if ($type == 'dir' && $autofix) {
683 drupal_install_mkdir($file, $mask); 702 drupal_install_mkdir($file, $mask);
684 } 703 }
685 if (!file_exists($file)) { 704 if (!file_exists($file)) {
686 $return = FALSE; 705 $return = FALSE;
687 } 706 }
688 } 707 }
689 break; 708 break;
690 case FILE_READABLE: 709 case FILE_READABLE:
691 if (!is_readable($file) && !drupal_install_fix_file($file, $mask)) { 710 if (!is_readable($file)) {
692 $return = FALSE; 711 $return = FALSE;
693 } 712 }
694 break; 713 break;
695 case FILE_WRITABLE: 714 case FILE_WRITABLE:
696 if (!is_writable($file) && !drupal_install_fix_file($file, $mask)) { 715 if (!is_writable($file)) {
697 $return = FALSE; 716 $return = FALSE;
698 } 717 }
699 break; 718 break;
700 case FILE_EXECUTABLE: 719 case FILE_EXECUTABLE:
701 if (!is_executable($file) && !drupal_install_fix_file($file, $mask)) { 720 if (!is_executable($file)) {
702 $return = FALSE; 721 $return = FALSE;
703 } 722 }
704 break; 723 break;
705 case FILE_NOT_READABLE: 724 case FILE_NOT_READABLE:
706 if (is_readable($file) && !drupal_install_fix_file($file, $mask)) { 725 if (is_readable($file)) {
707 $return = FALSE; 726 $return = FALSE;
708 } 727 }
709 break; 728 break;
710 case FILE_NOT_WRITABLE: 729 case FILE_NOT_WRITABLE:
711 if (is_writable($file) && !drupal_install_fix_file($file, $mask)) { 730 if (is_writable($file)) {
712 $return = FALSE; 731 $return = FALSE;
713 } 732 }
714 break; 733 break;
715 case FILE_NOT_EXECUTABLE: 734 case FILE_NOT_EXECUTABLE:
716 if (is_executable($file) && !drupal_install_fix_file($file, $mask)) { 735 if (is_executable($file)) {
717 $return = FALSE; 736 $return = FALSE;
718 } 737 }
719 break; 738 break;
720 } 739 }
721 } 740 }
722 } 741 }
742 }
743 if (!$return && $autofix) {
744 return drupal_install_fix_file($file, $mask);
723 } 745 }
724 return $return; 746 return $return;
725 } 747 }
726 748
727 /** 749 /**
946 // we don't yet know where all the modules are located. 968 // we don't yet know where all the modules are located.
947 // @todo Remove as part of https://www.drupal.org/node/2186491 969 // @todo Remove as part of https://www.drupal.org/node/2186491
948 $drupal_root = \Drupal::root(); 970 $drupal_root = \Drupal::root();
949 $module_list = (new ExtensionDiscovery($drupal_root))->scan('module'); 971 $module_list = (new ExtensionDiscovery($drupal_root))->scan('module');
950 972
951 foreach ($info['dependencies'] as $module) { 973 foreach ($info['install'] as $module) {
952 // If the module is in the module list we know it exists and we can continue 974 // If the module is in the module list we know it exists and we can continue
953 // including and registering it. 975 // including and registering it.
954 // @see \Drupal\Core\Extension\ExtensionDiscovery::scanDirectory() 976 // @see \Drupal\Core\Extension\ExtensionDiscovery::scanDirectory()
955 if (isset($module_list[$module])) { 977 if (isset($module_list[$module])) {
956 $function = $module . '_requirements'; 978 $function = $module . '_requirements';
965 987
966 if (function_exists($function)) { 988 if (function_exists($function)) {
967 $requirements = array_merge($requirements, $function('install')); 989 $requirements = array_merge($requirements, $function('install'));
968 } 990 }
969 } 991 }
992 }
993
994 // Add the profile requirements.
995 $function = $profile . '_requirements';
996 if (function_exists($function)) {
997 $requirements = array_merge($requirements, $function('install'));
970 } 998 }
971 999
972 return $requirements; 1000 return $requirements;
973 } 1001 }
974 1002
1011 if (isset($requirement['severity']) && $requirement['severity'] == REQUIREMENT_ERROR) { 1039 if (isset($requirement['severity']) && $requirement['severity'] == REQUIREMENT_ERROR) {
1012 $message = $requirement['description']; 1040 $message = $requirement['description'];
1013 if (isset($requirement['value']) && $requirement['value']) { 1041 if (isset($requirement['value']) && $requirement['value']) {
1014 $message = t('@requirements_message (Currently using @item version @version)', ['@requirements_message' => $requirement['description'], '@item' => $requirement['title'], '@version' => $requirement['value']]); 1042 $message = t('@requirements_message (Currently using @item version @version)', ['@requirements_message' => $requirement['description'], '@item' => $requirement['title'], '@version' => $requirement['value']]);
1015 } 1043 }
1016 drupal_set_message($message, 'error'); 1044 \Drupal::messenger()->addError($message);
1017 } 1045 }
1018 } 1046 }
1019 return FALSE; 1047 return FALSE;
1020 } 1048 }
1021 return TRUE; 1049 return TRUE;
1028 * in a normal Drupal module .info.yml file. For example: 1056 * in a normal Drupal module .info.yml file. For example:
1029 * - name: The real name of the installation profile for display purposes. 1057 * - name: The real name of the installation profile for display purposes.
1030 * - description: A brief description of the profile. 1058 * - description: A brief description of the profile.
1031 * - dependencies: An array of shortnames of other modules that this install 1059 * - dependencies: An array of shortnames of other modules that this install
1032 * profile requires. 1060 * profile requires.
1061 * - install: An array of shortname of other modules to install that are not
1062 * required by this install profile.
1033 * 1063 *
1034 * Additional, less commonly-used information that can appear in a 1064 * Additional, less commonly-used information that can appear in a
1035 * profile.info.yml file but not in a normal Drupal module .info.yml file 1065 * profile.info.yml file but not in a normal Drupal module .info.yml file
1036 * includes: 1066 * includes:
1037 * 1067 *
1045 * throughout the installation process. If omitted, 1075 * throughout the installation process. If omitted,
1046 * drupal_install_profile_distribution_name() defaults to 'Drupal'. 1076 * drupal_install_profile_distribution_name() defaults to 'Drupal'.
1047 * - install: Optional parameters to override the installer: 1077 * - install: Optional parameters to override the installer:
1048 * - theme: The machine name of a theme to use in the installer instead of 1078 * - theme: The machine name of a theme to use in the installer instead of
1049 * Drupal's default installer theme. 1079 * Drupal's default installer theme.
1080 * - finish_url: A destination to visit after the installation of the
1081 * distribution is finished
1050 * 1082 *
1051 * Note that this function does an expensive file system scan to get info file 1083 * Note that this function does an expensive file system scan to get info file
1052 * information for dependencies. If you only need information from the info 1084 * information for dependencies. If you only need information from the info
1053 * file itself, use system_get_info(). 1085 * file itself, use system_get_info().
1054 * 1086 *
1055 * Example of .info.yml file: 1087 * Example of .info.yml file:
1056 * @code 1088 * @code
1057 * name: Minimal 1089 * name: Minimal
1058 * description: Start fresh, with only a few modules enabled. 1090 * description: Start fresh, with only a few modules enabled.
1059 * dependencies: 1091 * install:
1060 * - block 1092 * - block
1061 * - dblog 1093 * - dblog
1062 * @endcode 1094 * @endcode
1063 * 1095 *
1064 * @param $profile 1096 * @param $profile
1074 1106
1075 if (!isset($cache[$profile][$langcode])) { 1107 if (!isset($cache[$profile][$langcode])) {
1076 // Set defaults for module info. 1108 // Set defaults for module info.
1077 $defaults = [ 1109 $defaults = [
1078 'dependencies' => [], 1110 'dependencies' => [],
1111 'install' => [],
1079 'themes' => ['stark'], 1112 'themes' => ['stark'],
1080 'description' => '', 1113 'description' => '',
1081 'version' => NULL, 1114 'version' => NULL,
1082 'hidden' => FALSE, 1115 'hidden' => FALSE,
1083 'php' => DRUPAL_MINIMUM_PHP, 1116 'php' => DRUPAL_MINIMUM_PHP,
1117 'config_install_path' => NULL,
1084 ]; 1118 ];
1085 $profile_file = drupal_get_path('profile', $profile) . "/$profile.info.yml"; 1119 $profile_path = drupal_get_path('profile', $profile);
1086 $info = \Drupal::service('info_parser')->parse($profile_file); 1120 $info = \Drupal::service('info_parser')->parse("$profile_path/$profile.info.yml");
1087 $info += $defaults; 1121 $info += $defaults;
1122
1123 // Convert dependencies in [project:module] format.
1124 $info['dependencies'] = array_map(function ($dependency) {
1125 return ModuleHandler::parseDependency($dependency)['name'];
1126 }, $info['dependencies']);
1127
1128 // Convert install key in [project:module] format.
1129 $info['install'] = array_map(function ($dependency) {
1130 return ModuleHandler::parseDependency($dependency)['name'];
1131 }, $info['install']);
1088 1132
1089 // drupal_required_modules() includes the current profile as a dependency. 1133 // drupal_required_modules() includes the current profile as a dependency.
1090 // Remove that dependency, since a module cannot depend on itself. 1134 // Remove that dependency, since a module cannot depend on itself.
1091 $required = array_diff(drupal_required_modules(), [$profile]); 1135 $required = array_diff(drupal_required_modules(), [$profile]);
1092 1136
1093 $locale = !empty($langcode) && $langcode != 'en' ? ['locale'] : []; 1137 $locale = !empty($langcode) && $langcode != 'en' ? ['locale'] : [];
1094 1138
1095 $info['dependencies'] = array_unique(array_merge($required, $info['dependencies'], $locale)); 1139 // Merge dependencies, required modules and locale into install list and
1096 1140 // remove any duplicates.
1141 $info['install'] = array_unique(array_merge($info['install'], $required, $info['dependencies'], $locale));
1142
1143 // If the profile has a config/sync directory use that to install drupal.
1144 if (is_dir($profile_path . '/config/sync')) {
1145 $info['config_install_path'] = $profile_path . '/config/sync';
1146 }
1097 $cache[$profile][$langcode] = $info; 1147 $cache[$profile][$langcode] = $info;
1098 } 1148 }
1099 return $cache[$profile][$langcode]; 1149 return $cache[$profile][$langcode];
1100 } 1150 }
1101 1151