diff --git a/core/includes/errors.inc b/core/includes/errors.inc
index 5fc4b7d..f29def7 100644
--- a/core/includes/errors.inc
+++ b/core/includes/errors.inc
@@ -153,7 +153,7 @@ function _drupal_render_exception_safe($exception) {
* TRUE if an error should be displayed.
*/
function error_displayable($error = NULL) {
- $error_level = config('system.logging')->get('error_level');
+ $error_level = _drupal_get_error_level();
$updating = (defined('MAINTENANCE_MODE') && MAINTENANCE_MODE == 'update');
$all_errors_displayed = ($error_level == ERROR_REPORTING_DISPLAY_ALL) ||
($error_level == ERROR_REPORTING_DISPLAY_VERBOSE);
@@ -254,7 +254,7 @@ function _drupal_log_error($error, $fatal = FALSE) {
$message = format_string('%type: !message in %function (line %line of %file).', $error);
// Check if verbose error reporting is on.
- $error_level = config('system.logging')->get('error_level');
+ $error_level = _drupal_get_error_level();
if ($error_level == ERROR_REPORTING_DISPLAY_VERBOSE) {
// First trace is the error itself, already contained in the message.
@@ -287,6 +287,29 @@ function _drupal_log_error($error, $fatal = FALSE) {
}
/**
+ * Returns the current error level.
+ *
+ * This function should only be used to get the current error level pre
+ * DRUPAL_BOOTSTRAP_KERNEL or before Drupal is installed. In all other
+ * situations the following code is preferred:
+ * @code
+ * Drupal::config('system.logging')->get('error_level');
+ * @endcode
+ *
+ * @return string
+ * The current error level.
+ */
+function _drupal_get_error_level() {
+ try {
+ return Drupal::config('system.logging')->get('error_level');
+ }
+ catch (Exception $e) {
+ // During very early install the cache_config table does not exist.
+ return ERROR_REPORTING_DISPLAY_ALL;
+ }
+}
+
+/**
* Gets the last caller from a backtrace.
*
* @param $backtrace
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index df688ab..b623e7d 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -1,5 +1,6 @@
getNamespaceName();
@@ -1057,8 +1065,11 @@ function install_settings_form_validate($form, &$form_state) {
$database['driver'] = $driver;
// TODO: remove when PIFR will be updated to use 'db_prefix' instead of
- // 'prefix' in the database settings form.
- $database['prefix'] = $database['db_prefix'];
+ // 'prefix' in the database settings form with the non-interactive
+ // installer.
+ if (!$test_prefix) {
+ $database['prefix'] = $database['db_prefix'];
+ }
unset($database['db_prefix']);
$form_state['storage']['database'] = $database;
@@ -1118,14 +1129,34 @@ function install_settings_form_submit($form, &$form_state) {
global $install_state;
// Update global settings array and save.
- $settings['databases'] = (object) array(
- 'value' => array('default' => array('default' => $form_state['storage']['database'])),
- 'required' => TRUE,
- );
- $settings['drupal_hash_salt'] = (object) array(
- 'value' => drupal_hash_base64(drupal_random_bytes(55)),
- 'required' => TRUE,
- );
+ $settings = array();
+ $database = $form_state['storage']['database'];
+ if ($test_prefix = drupal_valid_test_ua()) {
+ // This is test specific code, however it is very small and contained.
+ foreach ($form_state['storage']['database'] as $k => $v) {
+ if ($k != 'password') {
+ $settings['databases']['default']['default'][$k] = (object) array(
+ 'value' => $v,
+ 'required' => TRUE,
+ );
+ }
+ }
+ }
+ else {
+ // Because of the test specific code above, this assignment here must be
+ // kept simple and must not call any functions to avoid creating a tested
+ // and a non-tested code path.
+ $settings['databases']['default']['default'] = (object) array(
+ 'value' => $database,
+ 'required' => TRUE,
+ );
+ }
+ if (!$test_prefix) {
+ $settings['drupal_hash_salt'] = (object) array(
+ 'value' => drupal_hash_base64(drupal_random_bytes(55)),
+ 'required' => TRUE,
+ );
+ }
drupal_rewrite_settings($settings);
@@ -1609,7 +1640,7 @@ function install_already_done_error() {
global $base_url;
drupal_set_title(st('Drupal already installed'));
- return st('
- To start over, you must empty your existing database.
- To install to a different database, edit the appropriate settings.php file in the sites folder.
- To upgrade an existing installation, proceed to the update script.
- View your existing site.
', array('@base-url' => $base_url));
+ return st('- To start over, you must empty your existing database and delete your active configuration.
- To install to a different database, edit the appropriate settings.php file in the sites folder.
- To locate your active configuration, view the appropriate settings.php file in the sites folder.
- To upgrade an existing installation, proceed to the update script.
- View your existing site.
', array('@base-url' => $base_url));
}
/**
diff --git a/core/includes/theme.maintenance.inc b/core/includes/theme.maintenance.inc
index 37775e6..cda4109 100644
--- a/core/includes/theme.maintenance.inc
+++ b/core/includes/theme.maintenance.inc
@@ -50,7 +50,17 @@ function _drupal_maintenance_theme() {
// Stark otherwise. Since there is no low-level access to configuration
// currently, we only consult settings.php and fall back to Bartik
// otherwise, as it looks generic enough and way more user-friendly.
- $custom_theme = variable_get('maintenance_theme', config('system.theme')->get('default')) ?: 'bartik';
+ $custom_theme = variable_get('maintenance_theme');
+ if (!$custom_theme) {
+ $config = Drupal::config('system.theme');
+ // A broken install might not return an object.
+ if (is_object($config)) {
+ $custom_theme = $config->get('default');
+ }
+ }
+ if (!$custom_theme) {
+ $custom_theme = 'bartik';
+ }
}
// Ensure that system.module is loaded.
diff --git a/core/lib/Drupal/Core/SystemListingInfo.php b/core/lib/Drupal/Core/SystemListingInfo.php
index b2e42e1..989b0f2 100644
--- a/core/lib/Drupal/Core/SystemListingInfo.php
+++ b/core/lib/Drupal/Core/SystemListingInfo.php
@@ -28,7 +28,7 @@ protected function profiles($directory) {
// For SimpleTest to be able to test modules packaged together with a
// distribution we need to include the profile of the parent site (in
// which test runs are triggered).
- if (drupal_valid_test_ua()) {
+ if (drupal_valid_test_ua() && !drupal_installation_attempted()) {
$testing_profile = config('simpletest.settings')->get('parent_profile');
if ($testing_profile && $testing_profile != $profile) {
$searchdir[] = drupal_get_path('profile', $testing_profile) . '/' . $directory;
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/Tests/SimpleTestTest.php b/core/modules/simpletest/lib/Drupal/simpletest/Tests/SimpleTestTest.php
index a4641f6..e74b163 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/Tests/SimpleTestTest.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/Tests/SimpleTestTest.php
@@ -64,13 +64,6 @@ function testInternalBrowser() {
)));
$this->assertNoTitle('Foo');
- // Make sure that we are locked out of the installer when prefixing
- // using the user-agent header. This is an important security check.
- global $base_url;
-
- $this->drupalGet($base_url . '/core/install.php', array('external' => TRUE));
- $this->assertResponse(403, 'Cannot access install.php with a "simpletest" user-agent header.');
-
$user = $this->drupalCreateUser();
$this->drupalLogin($user);
$headers = $this->drupalGetHeaders(TRUE);
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
index 4e7b6b1..b24bba3 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
@@ -1358,9 +1358,9 @@ protected function drupalPost($path, $edit, $submit, array $options = array(), a
$this->fail(t('Failed to set field @name to @value', array('@name' => $name, '@value' => $value)));
}
if (!$ajax && isset($submit)) {
- $this->assertTrue($submit_matches, t('Found the @submit button', array('@submit' => $submit)));
+ $this->assertTrue($submit_matches, format_string('Found the @submit button', array('@submit' => $submit)));
}
- $this->fail(t('Found the requested form fields at @path', array('@path' => $path)));
+ $this->fail(format_string('Found the requested form fields at @path', array('@path' => $path)));
}
}
diff --git a/core/modules/system/lib/Drupal/system/Tests/InstallerTest.php b/core/modules/system/lib/Drupal/system/Tests/InstallerTest.php
new file mode 100644
index 0000000..5afb59e
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/InstallerTest.php
@@ -0,0 +1,138 @@
+ 'Installer tests',
+ 'description' => 'Tests the interactive installer.',
+ 'group' => 'Devilry',
+ );
+ }
+
+ protected function setUp() {
+ global $conf;
+
+ // When running tests through the Simpletest UI (vs. on the command line),
+ // Simpletest's batch conflicts with the installer's batch. Batch API does
+ // not support the concept of nested batches (in which the nested is not
+ // progressive), so we need to temporarily pretend there was no batch.
+ // Backup the currently running Simpletest batch.
+ $this->originalBatch = batch_get();
+
+ // Create the database prefix for this test.
+ $this->prepareDatabasePrefix();
+
+ // Prepare the environment for running tests.
+ $this->prepareEnvironment();
+ if (!$this->setupEnvironment) {
+ return FALSE;
+ }
+
+ // Reset all statics and variables to perform tests in a clean environment.
+ $conf = array();
+ drupal_static_reset();
+
+ // Change the database prefix.
+ // All static variables need to be reset before the database prefix is
+ // changed, since Drupal\Core\Utility\CacheArray implementations attempt to
+ // write back to persistent caches when they are destructed.
+ $this->changeDatabasePrefix();
+ if (!$this->setupDatabasePrefix) {
+ return FALSE;
+ }
+ $variable_groups = array(
+ 'system.file' => array(
+ 'path.private' => $this->private_files_directory,
+ 'path.temporary' => $this->temp_files_directory,
+ ),
+ 'locale.settings' => array(
+ 'translation.path' => $this->translation_files_directory,
+ ),
+ );
+ foreach ($variable_groups as $config_base => $variables) {
+ foreach ($variables as $name => $value) {
+ NestedArray::setValue($GLOBALS['conf'], array_merge(array($config_base), explode('.', $name)), $value);
+ }
+ }
+ $GLOBALS['conf']['file_public_path'] = $this->public_files_directory;
+ $settings['conf_path'] = (object) array(
+ 'value' => $this->public_files_directory,
+ 'required' => TRUE,
+ );
+ $settings['config_directories'] = (object) array(
+ 'value' => array(),
+ 'required' => TRUE,
+ );
+ $this->writeSettings($settings);
+
+ $this->drupalGet('core/install.php?langcode=en&profile=minimal');
+ $this->drupalPost(NULL, array(), 'Save and continue');
+ // Reload config directories.
+ include $this->public_files_directory . '/settings.php';
+ $prefix = substr($this->public_files_directory, strlen(conf_path() . '/files/'));
+ foreach ($config_directories as $type => $data) {
+ $GLOBALS['config_directories'][$type]['path'] = $prefix . '/files/' . $data['path'];
+ }
+ $this->rebuildContainer();
+
+ foreach ($variable_groups as $config_base => $variables) {
+ $config = config($config_base);
+ foreach ($variables as $name => $value) {
+ $config->set($name, $value);
+ }
+ $config->save();
+ }
+ variable_set('file_public_path', $this->public_files_directory);
+
+ // Use the test mail class instead of the default mail handler class.
+ config('system.mail')->set('interface.default', 'Drupal\Core\Mail\VariableLog')->save();
+
+ drupal_set_time_limit($this->timeLimit);
+ // Temporary fix so that when running from run-tests.sh we don't get an
+ // empty current path which would indicate we're on the home page.
+ $path = current_path();
+ if (empty($path)) {
+ _current_path('run-tests');
+ }
+ $this->setup = TRUE;
+ }
+
+ protected function refreshVariables() {
+ if (!empty($this->setup)) {
+ parent::refreshVariables();
+ }
+ }
+
+ protected function drupalGet($path, array $options = array(), array $headers = array()) {
+
+ // We re-using a CURL connection here. If that connection still has certain
+ // options set, it might change the GET into a POST. Make sure we clear out
+ // previous options.
+ $out = $this->curlExec(array(CURLOPT_HTTPGET => TRUE, CURLOPT_URL => $this->getAbsoluteUrl($path), CURLOPT_NOBODY => FALSE, CURLOPT_HTTPHEADER => $headers));
+ $this->refreshVariables(); // Ensure that any changes to variables in the other thread are picked up.
+
+ // Replace original page output with new output from redirected page(s).
+ if ($new = $this->checkForMetaRefresh()) {
+ $out = $new;
+ }
+ $this->verbose('GET request to: ' . $path .
+ '
Ending URL: ' . $this->getUrl() .
+ '
' . $out);
+ return $out;
+ }
+
+ function testInstaller() {
+ $this->drupalGet('user');
+ }
+}
\ No newline at end of file
diff --git a/core/modules/system/lib/Drupal/system/Tests/Upgrade/UpgradePathTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/UpgradePathTestBase.php
index 74c9923..c809829 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/UpgradePathTestBase.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/UpgradePathTestBase.php
@@ -73,7 +73,7 @@ protected function checkRequirements() {
* @see Drupal\simpletest\WebTestBase::changeDatabasePrefix()
* @see Drupal\simpletest\WebTestBase::prepareEnvironment()
*/
- protected function setUp() {
+ public function setUp() {
global $user, $conf;
// Load the Update API.
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index a93a124..445b27c 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -397,7 +397,9 @@ function system_requirements($phase) {
}
}
else {
- if (file_default_scheme() == 'public') {
+ // This function can be called before the config_cache table has been
+ // created.
+ if ($phase == 'install' || file_default_scheme() == 'public') {
$requirements['file system']['value'] = $t('Writable (public download method)');
}
else {
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index bdf5862..46f8807 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -719,6 +719,12 @@ function user_format_name($account) {
function user_template_preprocess_default_variables_alter(&$variables) {
global $user;
+ // If this function is called from the installer after Drupal has been
+ // installed then $user will not be set.
+ if (!is_object($user)) {
+ return;
+ }
+
$variables['user'] = clone $user;
// Remove password and session IDs, since themes should not need nor see them.
unset($variables['user']->pass, $variables['user']->sid, $variables['user']->ssid);