Skip to content
Snippets Groups Projects
Commit 3273a22e authored by Lucas Hedding's avatar Lucas Hedding Committed by Lucas Hedding
Browse files

Issue #3088474 by heddn: Add an opcache clearing mechanism

parent 4853a4ec
No related branches found
No related tags found
No related merge requests found
...@@ -103,6 +103,10 @@ services: ...@@ -103,6 +103,10 @@ services:
- '@extension.list.theme' - '@extension.list.theme'
tags: tags:
- { name: readiness_checker, category: warning} - { name: readiness_checker, category: warning}
automatic_updates.opcode_cache:
class: Drupal\automatic_updates\ReadinessChecker\OpcodeCache
tags:
- { name: readiness_checker, category: error}
automatic_updates.php_sapi: automatic_updates.php_sapi:
class: Drupal\automatic_updates\ReadinessChecker\PhpSapi class: Drupal\automatic_updates\ReadinessChecker\PhpSapi
arguments: arguments:
......
...@@ -40,12 +40,12 @@ trait ProjectInfoTrait { ...@@ -40,12 +40,12 @@ trait ProjectInfoTrait {
$file_paths = $this->getExtensionList($extension_type)->getPathnames(); $file_paths = $this->getExtensionList($extension_type)->getPathnames();
$infos = $this->getExtensionList($extension_type)->getAllAvailableInfo(); $infos = $this->getExtensionList($extension_type)->getAllAvailableInfo();
array_walk($infos, function (array &$info, $key) use ($file_paths) { array_walk($infos, function (array &$info, $key) use ($file_paths) {
$info['packaged'] = $info['project'] ?? FALSE; $info['packaged'] = isset($info['project']) ? $info['project'] : FALSE;
$info['install path'] = $file_paths[$key] ? dirname($file_paths[$key]) : ''; $info['install path'] = $file_paths[$key] ? dirname($file_paths[$key]) : '';
$info['project'] = $this->getProjectName($key, $info); $info['project'] = $this->getProjectName($key, $info);
$info['version'] = $this->getExtensionVersion($info); $info['version'] = $this->getExtensionVersion($info);
}); });
$system = $infos['system'] ?? NULL; $system = isset($infos['system']) ? $infos['system'] : NULL;
$infos = array_filter($infos, function (array $info, $project_name) { $infos = array_filter($infos, function (array $info, $project_name) {
return $info && $info['project'] === $project_name; return $info && $info['project'] === $project_name;
}, ARRAY_FILTER_USE_BOTH); }, ARRAY_FILTER_USE_BOTH);
......
<?php
namespace Drupal\automatic_updates\ReadinessChecker;
use Drupal\Core\StringTranslation\StringTranslationTrait;
/**
* Error if opcode caching is enabled and updates are executed via CLI.
*/
class OpcodeCache implements ReadinessCheckerInterface {
use StringTranslationTrait;
/**
* {@inheritdoc}
*/
public function run() {
$messages = [];
if ($this->isCli() && $this->hasOpcodeFileCache()) {
$messages[] = $this->t('Automatic updates cannot run via CLI when opcode file cache is enabled.');
}
return $messages;
}
/**
* Determine if PHP is running via CLI.
*
* @return bool
* TRUE if CLI, FALSE otherwise.
*/
protected function isCli() {
return PHP_SAPI === 'cli';
}
/**
* Determine if opcode cache is enabled.
*
* If opcache.validate_timestamps is disabled or enabled with
* opcache.revalidate_freq greater then 2, then a site is considered to have
* opcode caching. The default php.ini setup is
* opcache.validate_timestamps=TRUE and opcache.revalidate_freq=2.
*
* @return bool
* TRUE if opcode file cache is enabled, FALSE otherwise.
*/
protected function hasOpcodeFileCache() {
if (!ini_get('opcache.validate_timestamps')) {
return TRUE;
}
if (ini_get('opcache.revalidate_freq') > 2) {
return TRUE;
}
return FALSE;
}
}
...@@ -153,6 +153,9 @@ class InPlaceUpdate implements UpdateInterface { ...@@ -153,6 +153,9 @@ class InPlaceUpdate implements UpdateInterface {
if (!$success) { if (!$success) {
$this->rollback($project_root); $this->rollback($project_root);
} }
else {
$this->clearOpcodeCache();
}
} }
} }
return $success; return $success;
...@@ -561,4 +564,13 @@ class InPlaceUpdate implements UpdateInterface { ...@@ -561,4 +564,13 @@ class InPlaceUpdate implements UpdateInterface {
return new \ArrayIterator($deletions); return new \ArrayIterator($deletions);
} }
/**
* Clear opcode cache on successful update.
*/
protected function clearOpcodeCache() {
if (function_exists('opcache_reset')) {
opcache_reset();
}
}
} }
<?php
namespace Drupal\Tests\automatic_updates\Kernel\ReadinessChecker;
use Drupal\KernelTests\KernelTestBase;
/**
* Tests opcode caching and execution via CLI.
*
* @group automatic_updates
*/
class OpcodeCacheTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
public static $modules = [
'automatic_updates',
];
/**
* Tests the functionality of supported PHP version readiness checks.
*
* @dataProvider opcodeCacheProvider
*/
public function testOpcodeCache($ini, $ini_value, $failure) {
ini_set($ini, $ini_value);
$messages = $this->container->get('automatic_updates.opcode_cache')->run();
if ($failure) {
$this->assertNotEmpty($messages);
$this->assertEquals((string) $messages[0], 'Automatic updates cannot run via CLI when opcode file cache is enabled.');
}
else {
$this->assertEmpty($messages);
}
}
/**
* Data provider for opcode cache testing.
*/
public function opcodeCacheProvider() {
$datum[] = [
'ini' => 'opcache.validate_timestamps',
'ini_value' => 0,
'failure' => TRUE,
];
$datum[] = [
'ini' => 'opcache.validate_timestamps',
'ini_value' => 1,
'failure' => FALSE,
];
$datum[] = [
'ini' => 'opcache.validate_timestamps',
'ini_value' => FALSE,
'failure' => TRUE,
];
$datum[] = [
'ini' => 'opcache.validate_timestamps',
'ini_value' => TRUE,
'failure' => FALSE,
];
$datum[] = [
'ini' => 'opcache.validate_timestamps',
'ini_value' => 2,
'failure' => FALSE,
];
$datum[] = [
'ini' => 'opcache.revalidate_freq',
'ini_value' => 3,
'failure' => TRUE,
];
$datum[] = [
'ini' => 'opcache.revalidate_freq',
'ini_value' => 2,
'failure' => FALSE,
];
return $datum;
}
}
...@@ -19,9 +19,9 @@ class PhpSapiTest extends KernelTestBase { ...@@ -19,9 +19,9 @@ class PhpSapiTest extends KernelTestBase {
]; ];
/** /**
* Tests the functionality of supported PHP version readiness checks. * Tests PHP SAPI changes.
*/ */
public function testSupportedPhpVersion() { public function testPhpSapiChanges() {
$messages = $this->container->get('automatic_updates.php_sapi')->run(); $messages = $this->container->get('automatic_updates.php_sapi')->run();
$this->assertEmpty($messages); $this->assertEmpty($messages);
$messages = $this->container->get('automatic_updates.php_sapi')->run(); $messages = $this->container->get('automatic_updates.php_sapi')->run();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment