cdn.requirements.inc in CDN 6.2
Functionality to automatically detect if a patch has been applied.
File
cdn.requirements.incView source
<?php
/**
* @file
* Functionality to automatically detect if a patch has been applied.
*/
/**
* Generates a requirement for the given patch.
*/
function _cdn_requirements_generate_requirement_for_patch(&$requirements, $patch_name, $title, $not_properly_applied_severity = REQUIREMENT_ERROR) {
$t = get_t();
$patterns_function = '_cdn_requirements_' . $patch_name . '_patch_patterns';
$patterns = $patterns_function();
// No patterns means the patch file could not be found.
if ($patterns !== FALSE) {
$unpatched_files = _cdn_requirements_check_patch_applied($patterns);
}
$key = 'cdn_' . $patch_name . '_patch';
$requirements[$key]['title'] = $title;
if ($patterns === FALSE) {
$requirements[$key] += array(
'description' => $t('This patch file has been moved or deleted by the administrator. Please restore it, so we can verify that the patch has been properly applied.'),
'severity' => REQUIREMENT_ERROR,
'value' => $t('Unable to check'),
);
}
elseif (count($unpatched_files) == 0) {
$requirements[$key] += array(
'severity' => REQUIREMENT_OK,
'value' => $t('Applied'),
);
}
else {
$requirements[$key] += array(
'description' => $t('This patch has not been properly applied to the following files (or the patch has been updated):') . '<br />' . theme('item_list', $unpatched_files) . '<br />' . t('Please consult the installation instructions in the included README.txt.'),
'severity' => $not_properly_applied_severity,
'value' => $t('Not/incompletely applied patch or updated patch.'),
);
}
}
/**
* Check if a patch has been applied, given a set of patterns.
*/
function _cdn_requirements_check_patch_applied($patterns) {
$drupal_root = realpath('.');
$patched = TRUE;
$unpatched_files = array();
foreach ($patterns as $kind => $details) {
foreach ($details as $file_info => $patterns) {
foreach ($patterns as $pattern) {
if ($kind == 'core') {
$filename = $file_info;
$full_path = $drupal_root . '/' . $filename;
}
else {
list($name, $filename) = explode('|', $file_info);
$full_path = $drupal_root . '/' . drupal_get_path($kind, $name) . '/' . $filename;
}
if ($full_path) {
$match = preg_match('|' . preg_quote($pattern) . '|m', file_get_contents($full_path));
// If it didn't match, try allowing \r\n line endings and see if it
// it then matches. This is of course also qualifies as a correctly
// applied patch.
if (!$match) {
$match = preg_match('|' . preg_quote($pattern) . '|m', str_replace("\n", "\r\n", file_get_contents($full_path)));
}
$patched = $patched && $match;
// Remember unpatched files.
if (!$match && !in_array($full_path, $unpatched_files)) {
$unpatched_files[] = $full_path;
}
}
}
}
}
return $unpatched_files;
}
/**
* Generate patterns for a patch, given the full path to a patch. This
* effectively parses the patch and stores it in a meaningful structure.
*/
function _cdn_requirements_generate_patterns_for_patch($full_path) {
// The patch file must exist, otherwise we can't generate any patterns.
if (!file_exists($full_path)) {
return FALSE;
}
$fp = fopen($full_path, 'r');
$patch_block = '';
while (!feof($fp)) {
$line = fgets($fp);
// Check if the current line indicates the next file.
if (drupal_substr($line, 0, 13) == 'diff --git a/') {
$file_to_patch = drupal_substr($line, 13, strpos($line, ' ', 13) - 13);
}
// Finally, store the lines that have been added (+): concatenate them in
// a "patch block".
if ($line[0] == '+' && ($line[1] == ' ' || $line[1] == "\n")) {
$patch_block .= drupal_substr($line, 1);
}
else {
if ($patch_block != '') {
$patterns['core'][$file_to_patch][] = $patch_block;
}
$patch_block = '';
}
}
fclose($fp);
return $patterns;
}
/**
* Generates the patterns for the core patch.
*/
function _cdn_requirements_core_patch_patterns() {
return _cdn_requirements_generate_patterns_for_patch(dirname(__FILE__) . '/patches/drupal6.patch');
}
/**
* Checks if the used Drupal distribution is already patched or not.
* (This is the case when either Pressflow or Cocomore is being used).
*/
function _cdn_requirements_is_patched_distribution() {
$profile = realpath('.') . '/profiles/default/default.profile';
if (!file_exists($profile)) {
return FALSE;
}
include_once $profile;
$default = default_profile_details();
if ($default['name'] == 'Pressflow') {
return 'pressflow';
}
if (stristr($default['name'], 'cocomore')) {
return 'cocomore';
}
return FALSE;
}
/**
* Detect whether the fallback mechanism (to alter file URLs, the best
* mechanism is the core patch, but a fallback to the theme layer is included)
* should be enabled or disabled, and actually enable/disable it, too.
*/
function _cdn_requirements_detect_fallback() {
// Check if the core patch is applied properly (i.e. no core files don't
// properly match the core patch). If it is properly applied, then the
// fallback will be (or remain) disabled, if not, then the fallback will be
// (or remain) enabled.
$fallback_currently_enabled = variable_get(CDN_THEME_LAYER_FALLBACK_VARIABLE, FALSE);
if (_cdn_requirements_is_patched_distribution() === FALSE && count(_cdn_requirements_check_patch_applied(_cdn_requirements_core_patch_patterns())) > 0) {
if (!$fallback_currently_enabled) {
variable_set(CDN_THEME_LAYER_FALLBACK_VARIABLE, TRUE);
drupal_rebuild_theme_registry();
drupal_set_message(t("Drupal CDN integration status changed: core patch not (properly) applied; fallback mechanism enabled."), 'warning');
watchdog('cdn', "Drupal CDN integration status changed: core patch not (properly) applied; fallback mechanism enabled.");
}
}
else {
if ($fallback_currently_enabled) {
variable_set(CDN_THEME_LAYER_FALLBACK_VARIABLE, FALSE);
drupal_rebuild_theme_registry();
drupal_set_message(t("Drupal CDN integration status changed: core patch properly applied; fallback mechanism disabled."), 'warning');
watchdog('cdn', "Drupal CDN integration status changed: core patch properly applied; fallback mechanism disabled.");
}
}
}
/**
* Get the integration mechanism that is currently being used by the CDN
* integration module.
*
* @return
* One of the following: 'fallback', 'pressflow', 'cocomore', 'core patch'.
*/
function _cdn_requirements_get_integration_mechanism() {
if (variable_get(CDN_THEME_LAYER_FALLBACK_VARIABLE, FALSE)) {
return 'fallback';
}
elseif (($drupal_profile = _cdn_requirements_is_patched_distribution()) !== FALSE) {
return $drupal_profile;
}
else {
return 'core patch';
}
}
Functions
Name | Description |
---|---|
_cdn_requirements_check_patch_applied | Check if a patch has been applied, given a set of patterns. |
_cdn_requirements_core_patch_patterns | Generates the patterns for the core patch. |
_cdn_requirements_detect_fallback | Detect whether the fallback mechanism (to alter file URLs, the best mechanism is the core patch, but a fallback to the theme layer is included) should be enabled or disabled, and actually enable/disable it, too. |
_cdn_requirements_generate_patterns_for_patch | Generate patterns for a patch, given the full path to a patch. This effectively parses the patch and stores it in a meaningful structure. |
_cdn_requirements_generate_requirement_for_patch | Generates a requirement for the given patch. |
_cdn_requirements_get_integration_mechanism | Get the integration mechanism that is currently being used by the CDN integration module. |
_cdn_requirements_is_patched_distribution | Checks if the used Drupal distribution is already patched or not. (This is the case when either Pressflow or Cocomore is being used). |