diff --git a/core/modules/auto_updates/auto_updates.install b/core/modules/auto_updates/auto_updates.install
index 173d1ceaef..7994d74219 100644
--- a/core/modules/auto_updates/auto_updates.install
+++ b/core/modules/auto_updates/auto_updates.install
@@ -34,7 +34,7 @@ function auto_updates_requirements($phase) {
]);
}
}
- elseif (\Drupal::time()->getRequestTime() > $last_check_timestamp + ReadinessCheckerManagerInterface::LAST_CHECKED_WARNING) {
+ elseif (!$checker_manager->hasRunRecently()) {
$requirements['auto_updates_readiness']['severity'] = REQUIREMENT_ERROR;
$time_ago = \Drupal::service('date.formatter')->formatTimeDiffSince($last_check_timestamp);
$requirements['auto_updates_readiness']['value'] = t('Your site has not recently checked if it is ready to apply automatic updates.', ['@readiness_checks' => 'https://www.drupal.org/docs/8/update/automatic-updates#readiness-checks']);
diff --git a/core/modules/auto_updates/auto_updates.module b/core/modules/auto_updates/auto_updates.module
index 70a68230aa..800549bec2 100644
--- a/core/modules/auto_updates/auto_updates.module
+++ b/core/modules/auto_updates/auto_updates.module
@@ -32,15 +32,14 @@ function auto_updates_page_top(array &$page_top) {
if (in_array(\Drupal::routeMatch()->getRouteName(), $disabled_routes, TRUE)) {
return;
}
- $last_check_timestamp = \Drupal::service('auto_updates.readiness_checker_manager')->timestamp();
- if (\Drupal::time()->getRequestTime() > $last_check_timestamp + ReadinessCheckerManagerInterface::LAST_CHECKED_WARNING) {
+ /** @var \Drupal\auto_updates\ReadinessChecker\ReadinessCheckerManagerInterface $checker_manager */
+ $checker_manager = \Drupal::service('auto_updates.readiness_checker_manager');
+ if (!$checker_manager->hasRunRecently()) {
$readiness_settings = Url::fromRoute('auto_updates.settings');
\Drupal::messenger()->addError(t('Your site has not recently run an update readiness check. Administer automatic updates and run readiness checks manually.', [
':url' => $readiness_settings->toString(),
]));
}
- /** @var \Drupal\auto_updates\ReadinessChecker\ReadinessCheckerManagerInterface $checker_manager */
- $checker_manager = \Drupal::service('auto_updates.readiness_checker_manager');
$results = $checker_manager->getResults(ReadinessCheckerManagerInterface::ERROR);
if ($results) {
\Drupal::messenger()->addError(t('Your site is currently failing readiness checks for automatic updates. It cannot be automatically updated until further action is performed:', [':readiness_checks' => 'https://www.drupal.org/docs/8/update/auto-updates#readiness-checks']));
@@ -82,7 +81,7 @@ function auto_updates_cron() {
function auto_updates_modules_installed($modules) {
/** @var ReadinessCheckerManagerInterface $checker_manager */
$checker_manager = \Drupal::service('auto_updates.readiness_checker_manager');
- if ($checker_manager->clearResultsStaleResults()) {
+ if ($checker_manager->clearStaleResults()) {
$checker_manager->run();
}
}
diff --git a/core/modules/auto_updates/auto_updates.services.yml b/core/modules/auto_updates/auto_updates.services.yml
index 461fbcd4fb..4b8c52678b 100644
--- a/core/modules/auto_updates/auto_updates.services.yml
+++ b/core/modules/auto_updates/auto_updates.services.yml
@@ -6,6 +6,6 @@ services:
- { name: readiness_checker, category: error}
auto_updates.readiness_checker_manager:
class: Drupal\auto_updates\ReadinessChecker\ReadinessCheckerManager
- arguments: ['@keyvalue', '@config.factory']
+ arguments: ['@keyvalue', '@config.factory', '@datetime.time']
tags:
- { name: service_collector, tag: readiness_checker, call: addChecker }
diff --git a/core/modules/auto_updates/src/ReadinessChecker/DiskSpace.php b/core/modules/auto_updates/src/ReadinessChecker/DiskSpace.php
index 69bd3f6b22..42bd0acda4 100644
--- a/core/modules/auto_updates/src/ReadinessChecker/DiskSpace.php
+++ b/core/modules/auto_updates/src/ReadinessChecker/DiskSpace.php
@@ -10,12 +10,12 @@
class DiskSpace extends FilesystemBase {
/**
- * Minimum disk space (in bytes) is 10mb.
+ * Minimum disk space (in bytes) is 100mb.
*
* @todo Determine how much the minimum should be now that we will be using
- * Composer.
+ * Composer in https://www.drupal.org/node/3166416.
*/
- const MINIMUM_DISK_SPACE = 10000000;
+ const MINIMUM_DISK_SPACE = 100000000;
/**
* Megabyte divisor.
@@ -45,7 +45,7 @@ protected function diskSpaceCheck() {
'@space' => $minimum_megabytes,
]);
}
- if (is_dir($this->getVendorPath()) && disk_free_space($this->getVendorPath()) < static::MINIMUM_DISK_SPACE) {
+ if (disk_free_space($this->getVendorPath()) < static::MINIMUM_DISK_SPACE) {
$messages[] = $this->t('Vendor filesystem "@vendor" has insufficient space. There must be at least @space megabytes free.', [
'@vendor' => $this->getVendorPath(),
'@space' => $minimum_megabytes,
diff --git a/core/modules/auto_updates/src/ReadinessChecker/FilesystemBase.php b/core/modules/auto_updates/src/ReadinessChecker/FilesystemBase.php
index 622b7795d1..9b5c4b0f3a 100644
--- a/core/modules/auto_updates/src/ReadinessChecker/FilesystemBase.php
+++ b/core/modules/auto_updates/src/ReadinessChecker/FilesystemBase.php
@@ -17,13 +17,6 @@ abstract class FilesystemBase implements ReadinessCheckerInterface {
*/
protected $rootPath;
- /**
- * The vendor file path.
- *
- * @var string
- */
- protected $vendorPath;
-
/**
* Filesystem constructor.
*
@@ -38,10 +31,18 @@ public function __construct(string $app_root) {
* {@inheritdoc}
*/
public function run() {
+ $messages = [];
if (!file_exists($this->getRootPath() . DIRECTORY_SEPARATOR . implode(DIRECTORY_SEPARATOR, ['core', 'core.api.php']))) {
- return [$this->t('The web root could not be located.')];
+ $messages[] = $this->t('The web root could not be located.');
+ }
+ if (!is_dir($this->getVendorPath())) {
+ $messages[] = $this->t('Vendor folder "@vendor" is not a valid directory. Alternate vendor folder locations are not currently supported.', [
+ '@vendor' => $this->getVendorPath(),
+ ]);
+ }
+ if ($messages) {
+ return $messages;
}
-
return $this->doCheck();
}
@@ -60,9 +61,6 @@ public function run() {
* The root file path.
*/
protected function getRootPath() {
- if (!$this->rootPath) {
- $this->rootPath = (string) \Drupal::root();
- }
return $this->rootPath;
}
@@ -73,10 +71,9 @@ protected function getRootPath() {
* The vendor file path.
*/
protected function getVendorPath() {
- if (!$this->vendorPath) {
- $this->vendorPath = $this->getRootPath() . DIRECTORY_SEPARATOR . 'vendor';
- }
- return $this->vendorPath;
+ // @todo Support finding the 'vendor' directory dynamically in
+ // https://www.drupal.org/node/3166435.
+ return $this->getRootPath() . DIRECTORY_SEPARATOR . 'vendor';
}
/**
diff --git a/core/modules/auto_updates/src/ReadinessChecker/ReadinessCheckerManager.php b/core/modules/auto_updates/src/ReadinessChecker/ReadinessCheckerManager.php
index e813912603..42e2059156 100644
--- a/core/modules/auto_updates/src/ReadinessChecker/ReadinessCheckerManager.php
+++ b/core/modules/auto_updates/src/ReadinessChecker/ReadinessCheckerManager.php
@@ -2,6 +2,7 @@
namespace Drupal\auto_updates\ReadinessChecker;
+use Drupal\Component\Datetime\TimeInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\KeyValueStore\KeyValueFactoryInterface;
@@ -10,6 +11,11 @@
*/
class ReadinessCheckerManager implements ReadinessCheckerManagerInterface {
+ /**
+ * Last checked ago warning (in seconds).
+ */
+ private const LAST_CHECKED_WARNING = 3600 * 24;
+
/**
* The key/value storage.
*
@@ -34,6 +40,13 @@ class ReadinessCheckerManager implements ReadinessCheckerManagerInterface {
*/
protected $checkers = [];
+ /**
+ * The time service.
+ *
+ * @var \Drupal\Component\Datetime\TimeInterface
+ */
+ protected $time;
+
/**
* ReadinessCheckerManager constructor.
*
@@ -41,10 +54,13 @@ class ReadinessCheckerManager implements ReadinessCheckerManagerInterface {
* The key/value service.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory.
+ * @param \Drupal\Component\Datetime\TimeInterface $time
+ * The time service.
*/
- public function __construct(KeyValueFactoryInterface $key_value, ConfigFactoryInterface $config_factory) {
+ public function __construct(KeyValueFactoryInterface $key_value, ConfigFactoryInterface $config_factory, TimeInterface $time) {
$this->keyValue = $key_value->get('auto_updates');
$this->configFactory = $config_factory;
+ $this->time = $time;
}
/**
@@ -81,7 +97,7 @@ public function run() {
'checkers' => $this->getCurrentCheckerIds(),
]
);
- $this->keyValue->set('readiness_check_timestamp', \Drupal::time()->getRequestTime());
+ $this->keyValue->set('readiness_check_timestamp', $this->time->getRequestTime());
return $messages_by_category;
}
@@ -100,7 +116,7 @@ public function getResults($category) {
/**
* {@inheritdoc}
*/
- public function clearResultsStaleResults() {
+ public function clearStaleResults() {
$results = $this->keyValue->get('readiness_check_results');
if (isset($results['checkers']) && $this->getCurrentCheckerIds() !== $results['checkers']) {
$this->keyValue->delete('readiness_check_results');
@@ -133,10 +149,10 @@ public function getCategories() {
/**
* Sorts checkers according to priority.
*
- * @return \Drupal\auto_updates\ReadinessChecker\ReadinessCheckerInterface[]
- * A sorted array of checker objects.
- *
- * @todo Add more detail to @return.
+ * @return \Drupal\auto_updates\ReadinessChecker\ReadinessCheckerInterface[][]
+ * A nested and sorted array of checker objects. The first level of the
+ * array is keyed by checker categories. The second level array is checker
+ * objects in the category order by priority.
*/
protected function getSortedCheckers() {
$sorted = [];
@@ -166,4 +182,11 @@ protected function getCurrentCheckerIds(): string {
return implode('::', $service_ids);
}
+ /**
+ * {@inheritdoc}
+ */
+ public function hasRunRecently() {
+ return !($this->time->getRequestTime() > $this->timestamp() + self::LAST_CHECKED_WARNING);
+ }
+
}
diff --git a/core/modules/auto_updates/src/ReadinessChecker/ReadinessCheckerManagerInterface.php b/core/modules/auto_updates/src/ReadinessChecker/ReadinessCheckerManagerInterface.php
index b794df6af0..be26011f3f 100644
--- a/core/modules/auto_updates/src/ReadinessChecker/ReadinessCheckerManagerInterface.php
+++ b/core/modules/auto_updates/src/ReadinessChecker/ReadinessCheckerManagerInterface.php
@@ -17,11 +17,6 @@ interface ReadinessCheckerManagerInterface {
*/
const WARNING = 'warning';
- /**
- * Last checked ago warning (in seconds).
- */
- const LAST_CHECKED_WARNING = 3600 * 24;
-
/**
* Appends a checker to the checker chain.
*
@@ -90,6 +85,14 @@ public function getCategories();
* @return bool
* Return TRUE if the results were cleared, otherwise returns FALSE.
*/
- public function clearResultsStaleResults();
+ public function clearStaleResults();
+
+ /**
+ * Determines whether the readiness checkers have been run recently.
+ *
+ * @return bool
+ * True if the checkers have been run recently, otherwise false.
+ */
+ public function hasRunRecently();
}
diff --git a/core/modules/auto_updates/tests/src/Kernel/ReadinessChecker/DiskSpaceTest.php b/core/modules/auto_updates/tests/src/Kernel/ReadinessChecker/DiskSpaceTest.php
index 51a09e5aad..08066f8dcf 100644
--- a/core/modules/auto_updates/tests/src/Kernel/ReadinessChecker/DiskSpaceTest.php
+++ b/core/modules/auto_updates/tests/src/Kernel/ReadinessChecker/DiskSpaceTest.php
@@ -42,6 +42,13 @@ public function testDiskSpace() {
$this->assertStringMatchesFormat('Drupal root filesystem "%s" has insufficient space. There must be at least %s megabytes free.', (string) $messages[0]);
$this->assertStringMatchesFormat('Vendor filesystem "%s" has insufficient space. There must be at least %s megabytes free.', (string) $messages[1]);
$this->assertStringMatchesFormat('Directory "%s" has insufficient space. There must be at least %s megabytes free.', (string) $messages[2]);
+
+ // Web root and vendor path are invalid.
+ $disk_space = new DiskSpace("if_there_was_ever_a_folder_with_this_path_this_test_would_fail");
+ $messages = $disk_space->run();
+ $this->assertCount(2, $messages);
+ $this->assertEquals('The web root could not be located.', (string) $messages[0]);
+ $this->assertStringMatchesFormat('Vendor folder "if_there_was_ever_a_folder_with_this_path_this_test_would_fail/vendor" is not a valid directory. Alternate vendor folder locations are not currently supported.', (string) $messages[1]);
}
}