Mercurial > defr > drupal > core
comparison modules/update/update.compare.inc @ 1:c1f4ac30525a 6.0
Drupal 6.0
| author | Franck Deroche <webmaster@defr.org> |
|---|---|
| date | Tue, 23 Dec 2008 14:28:28 +0100 |
| parents | |
| children | acef7ccb09b5 |
comparison
equal
deleted
inserted
replaced
| 0:5a113a1c4740 | 1:c1f4ac30525a |
|---|---|
| 1 <?php | |
| 2 // $Id: update.compare.inc,v 1.8 2008/02/03 19:34:02 goba Exp $ | |
| 3 | |
| 4 /** | |
| 5 * @file | |
| 6 * Code required only when comparing available updates to existing data. | |
| 7 */ | |
| 8 | |
| 9 /** | |
| 10 * Fetch an array of installed and enabled projects. | |
| 11 * | |
| 12 * This is only responsible for generating an array of projects (taking into | |
| 13 * account projects that include more than one module or theme). Other | |
| 14 * information like the specific version and install type (official release, | |
| 15 * dev snapshot, etc) is handled later in update_process_project_info() since | |
| 16 * that logic is only required when preparing the status report, not for | |
| 17 * fetching the available release data. | |
| 18 * | |
| 19 * @see update_process_project_info() | |
| 20 * @see update_calculate_project_data() | |
| 21 * | |
| 22 */ | |
| 23 function update_get_projects() { | |
| 24 static $projects = array(); | |
| 25 if (empty($projects)) { | |
| 26 // Retrieve the projects from cache, if present. | |
| 27 $projects = update_project_cache('update_project_projects'); | |
| 28 if (empty($projects)) { | |
| 29 // Still empty, so we have to rebuild the cache. | |
| 30 _update_process_info_list($projects, module_rebuild_cache(), 'module'); | |
| 31 _update_process_info_list($projects, system_theme_data(), 'theme'); | |
| 32 // Set the projects array into the cache table. | |
| 33 cache_set('update_project_projects', $projects, 'cache_update', time() + 3600); | |
| 34 } | |
| 35 } | |
| 36 return $projects; | |
| 37 } | |
| 38 | |
| 39 /** | |
| 40 * Populate an array of project data. | |
| 41 */ | |
| 42 function _update_process_info_list(&$projects, $list, $project_type) { | |
| 43 foreach ($list as $file) { | |
| 44 if (empty($file->status)) { | |
| 45 // Skip disabled modules or themes. | |
| 46 continue; | |
| 47 } | |
| 48 | |
| 49 // Skip if the .info file is broken. | |
| 50 if (empty($file->info)) { | |
| 51 continue; | |
| 52 } | |
| 53 | |
| 54 // If the .info doesn't define the 'project', try to figure it out. | |
| 55 if (!isset($file->info['project'])) { | |
| 56 $file->info['project'] = update_get_project_name($file); | |
| 57 } | |
| 58 | |
| 59 // If we still don't know the 'project', give up. | |
| 60 if (empty($file->info['project'])) { | |
| 61 continue; | |
| 62 } | |
| 63 | |
| 64 // If we don't already know it, grab the change time on the .info file | |
| 65 // itself. Note: we need to use the ctime, not the mtime (modification | |
| 66 // time) since many (all?) tar implementations will go out of their way to | |
| 67 // set the mtime on the files it creates to the timestamps recorded in the | |
| 68 // tarball. We want to see the last time the file was changed on disk, | |
| 69 // which is left alone by tar and correctly set to the time the .info file | |
| 70 // was unpacked. | |
| 71 if (!isset($file->info['_info_file_ctime'])) { | |
| 72 $info_filename = dirname($file->filename) .'/'. $file->name .'.info'; | |
| 73 $file->info['_info_file_ctime'] = filectime($info_filename); | |
| 74 } | |
| 75 | |
| 76 $project_name = $file->info['project']; | |
| 77 if (!isset($projects[$project_name])) { | |
| 78 // Only process this if we haven't done this project, since a single | |
| 79 // project can have multiple modules or themes. | |
| 80 $projects[$project_name] = array( | |
| 81 'name' => $project_name, | |
| 82 'info' => $file->info, | |
| 83 'datestamp' => isset($file->info['datestamp']) ? $file->info['datestamp'] : 0, | |
| 84 'includes' => array($file->name => $file->info['name']), | |
| 85 'project_type' => $project_name == 'drupal' ? 'core' : $project_type, | |
| 86 ); | |
| 87 } | |
| 88 else { | |
| 89 $projects[$project_name]['includes'][$file->name] = $file->info['name']; | |
| 90 $projects[$project_name]['info']['_info_file_ctime'] = max($projects[$project_name]['info']['_info_file_ctime'], $file->info['_info_file_ctime']); | |
| 91 } | |
| 92 } | |
| 93 } | |
| 94 | |
| 95 /** | |
| 96 * Given a $file object (as returned by system_get_files_database()), figure | |
| 97 * out what project it belongs to. | |
| 98 * | |
| 99 * @see system_get_files_database() | |
| 100 */ | |
| 101 function update_get_project_name($file) { | |
| 102 $project_name = ''; | |
| 103 if (isset($file->info['project'])) { | |
| 104 $project_name = $file->info['project']; | |
| 105 } | |
| 106 elseif (isset($file->info['package']) && (strpos($file->info['package'], 'Core -') !== FALSE)) { | |
| 107 $project_name = 'drupal'; | |
| 108 } | |
| 109 elseif (in_array($file->name, array('bluemarine', 'chameleon', 'garland', 'marvin', 'minnelli', 'pushbutton'))) { | |
| 110 // Unfortunately, there's no way to tell if a theme is part of core, | |
| 111 // so we must hard-code a list here. | |
| 112 $project_name = 'drupal'; | |
| 113 } | |
| 114 return $project_name; | |
| 115 } | |
| 116 | |
| 117 /** | |
| 118 * Process the list of projects on the system to figure out the currently | |
| 119 * installed versions, and other information that is required before we can | |
| 120 * compare against the available releases to produce the status report. | |
| 121 * | |
| 122 * @param $projects | |
| 123 * Array of project information from update_get_projects(). | |
| 124 */ | |
| 125 function update_process_project_info(&$projects) { | |
| 126 foreach ($projects as $key => $project) { | |
| 127 // Assume an official release until we see otherwise. | |
| 128 $install_type = 'official'; | |
| 129 | |
| 130 $info = $project['info']; | |
| 131 | |
| 132 if (isset($info['version'])) { | |
| 133 // Check for development snapshots | |
| 134 if (preg_match('@(dev|HEAD)@', $info['version'])) { | |
| 135 $install_type = 'dev'; | |
| 136 } | |
| 137 | |
| 138 // Figure out what the currently installed major version is. We need | |
| 139 // to handle both contribution (e.g. "5.x-1.3", major = 1) and core | |
| 140 // (e.g. "5.1", major = 5) version strings. | |
| 141 $matches = array(); | |
| 142 if (preg_match('/^(\d+\.x-)?(\d+)\..*$/', $info['version'], $matches)) { | |
| 143 $info['major'] = $matches[2]; | |
| 144 } | |
| 145 elseif (!isset($info['major'])) { | |
| 146 // This would only happen for version strings that don't follow the | |
| 147 // drupal.org convention. We let contribs define "major" in their | |
| 148 // .info in this case, and only if that's missing would we hit this. | |
| 149 $info['major'] = -1; | |
| 150 } | |
| 151 } | |
| 152 else { | |
| 153 // No version info available at all. | |
| 154 $install_type = 'unknown'; | |
| 155 $info['version'] = t('Unknown'); | |
| 156 $info['major'] = -1; | |
| 157 } | |
| 158 | |
| 159 // Finally, save the results we care about into the $projects array. | |
| 160 $projects[$key]['existing_version'] = $info['version']; | |
| 161 $projects[$key]['existing_major'] = $info['major']; | |
| 162 $projects[$key]['install_type'] = $install_type; | |
| 163 unset($projects[$key]['info']); | |
| 164 } | |
| 165 } | |
| 166 | |
| 167 /** | |
| 168 * Given the installed projects and the available release data retrieved from | |
| 169 * remote servers, calculate the current status. | |
| 170 * | |
| 171 * This function is the heart of the update status feature. It iterates over | |
| 172 * every currently installed project. For each one, it first checks if the | |
| 173 * project has been flagged with a special status like "unsupported" or | |
| 174 * "insecure", or if the project node itself has been unpublished. In any of | |
| 175 * those cases, the project is marked with an error and the next project is | |
| 176 * considered. | |
| 177 * | |
| 178 * If the project itself is valid, the function decides what major release | |
| 179 * series to consider. The project defines what the currently supported major | |
| 180 * versions are for each version of core, so the first step is to make sure | |
| 181 * the current version is still supported. If so, that's the target version. | |
| 182 * If the current version is unsupported, the project maintainer's recommended | |
| 183 * major version is used. There's also a check to make sure that this function | |
| 184 * never recommends an earlier release than the currently installed major | |
| 185 * version. | |
| 186 * | |
| 187 * Given a target major version, it scans the available releases looking for | |
| 188 * the specific release to recommend (avoiding beta releases and development | |
| 189 * snapshots if possible). This is complicated to describe, but an example | |
| 190 * will help clarify. For the target major version, find the highest patch | |
| 191 * level. If there is a release at that patch level with no extra ("beta", | |
| 192 * etc), then we recommend the release at that patch level with the most | |
| 193 * recent release date. If every release at that patch level has extra (only | |
| 194 * betas), then recommend the latest release from the previous patch | |
| 195 * level. For example: | |
| 196 * | |
| 197 * 1.6-bugfix <-- recommended version because 1.6 already exists. | |
| 198 * 1.6 | |
| 199 * | |
| 200 * or | |
| 201 * | |
| 202 * 1.6-beta | |
| 203 * 1.5 <-- recommended version because no 1.6 exists. | |
| 204 * 1.4 | |
| 205 * | |
| 206 * It also looks for the latest release from the same major version, even a | |
| 207 * beta release, to display to the user as the "Latest version" option. | |
| 208 * Additionally, it finds the latest official release from any higher major | |
| 209 * versions that have been released to provide a set of "Also available" | |
| 210 * options. | |
| 211 * | |
| 212 * Finally, and most importantly, it keeps scanning the release history until | |
| 213 * it gets to the currently installed release, searching for anything marked | |
| 214 * as a security update. If any security updates have been found between the | |
| 215 * recommended release and the installed version, all of the releases that | |
| 216 * included a security fix are recorded so that the site administrator can be | |
| 217 * warned their site is insecure, and links pointing to the release notes for | |
| 218 * each security update can be included (which, in turn, will link to the | |
| 219 * official security announcements for each vulnerability). | |
| 220 * | |
| 221 * This function relies on the fact that the .xml release history data comes | |
| 222 * sorted based on major version and patch level, then finally by release date | |
| 223 * if there are multiple releases such as betas from the same major.patch | |
| 224 * version (e.g. 5.x-1.5-beta1, 5.x-1.5-beta2, and 5.x-1.5). Development | |
| 225 * snapshots for a given major version are always listed last. | |
| 226 * | |
| 227 * @param $available | |
| 228 * Array of data about available project releases. | |
| 229 * | |
| 230 * @see update_get_available() | |
| 231 * @see update_get_projects() | |
| 232 * @see update_process_project_info() | |
| 233 */ | |
| 234 function update_calculate_project_data($available) { | |
| 235 // Retrieve the projects from cache, if present. | |
| 236 $projects = update_project_cache('update_project_data'); | |
| 237 // If $projects is empty, then the cache must be rebuilt. | |
| 238 // Otherwise, return the cached data and skip the rest of the function. | |
| 239 if (!empty($projects)) { | |
| 240 return $projects; | |
| 241 } | |
| 242 $projects = update_get_projects(); | |
| 243 update_process_project_info($projects); | |
| 244 foreach ($projects as $project => $project_info) { | |
| 245 if (isset($available[$project])) { | |
| 246 | |
| 247 // If the project status is marked as something bad, there's nothing | |
| 248 // else to consider. | |
| 249 if (isset($available[$project]['project_status'])) { | |
| 250 switch ($available[$project]['project_status']) { | |
| 251 case 'insecure': | |
| 252 $projects[$project]['status'] = UPDATE_NOT_SECURE; | |
| 253 if (empty($projects[$project]['extra'])) { | |
| 254 $projects[$project]['extra'] = array(); | |
| 255 } | |
| 256 $projects[$project]['extra'][] = array( | |
| 257 'class' => 'project-not-secure', | |
| 258 'label' => t('Project not secure'), | |
| 259 'data' => t('This project has been labeled insecure by the Drupal security team, and is no longer available for download. Immediately disabling everything included by this project is strongly recommended!'), | |
| 260 ); | |
| 261 break; | |
| 262 case 'unpublished': | |
| 263 case 'revoked': | |
| 264 $projects[$project]['status'] = UPDATE_REVOKED; | |
| 265 if (empty($projects[$project]['extra'])) { | |
| 266 $projects[$project]['extra'] = array(); | |
| 267 } | |
| 268 $projects[$project]['extra'][] = array( | |
| 269 'class' => 'project-revoked', | |
| 270 'label' => t('Project revoked'), | |
| 271 'data' => t('This project has been revoked, and is no longer available for download. Disabling everything included by this project is strongly recommended!'), | |
| 272 ); | |
| 273 break; | |
| 274 case 'unsupported': | |
| 275 $projects[$project]['status'] = UPDATE_NOT_SUPPORTED; | |
| 276 if (empty($projects[$project]['extra'])) { | |
| 277 $projects[$project]['extra'] = array(); | |
| 278 } | |
| 279 $projects[$project]['extra'][] = array( | |
| 280 'class' => 'project-not-supported', | |
| 281 'label' => t('Project not supported'), | |
| 282 'data' => t('This project is no longer supported, and is no longer available for download. Disabling everything included by this project is strongly recommended!'), | |
| 283 ); | |
| 284 break; | |
| 285 default: | |
| 286 // Assume anything else (e.g. 'published') is valid and we should | |
| 287 // perform the rest of the logic in this function. | |
| 288 break; | |
| 289 } | |
| 290 } | |
| 291 | |
| 292 if (!empty($projects[$project]['status'])) { | |
| 293 // We already know the status for this project, so there's nothing | |
| 294 // else to compute. Just record everything else we fetched from the | |
| 295 // XML file into our projects array and move to the next project. | |
| 296 $projects[$project] += $available[$project]; | |
| 297 continue; | |
| 298 } | |
| 299 | |
| 300 // Figure out the target major version. | |
| 301 $existing_major = $project_info['existing_major']; | |
| 302 $supported_majors = array(); | |
| 303 if (isset($available[$project]['supported_majors'])) { | |
| 304 $supported_majors = explode(',', $available[$project]['supported_majors']); | |
| 305 } | |
| 306 elseif (isset($available[$project]['default_major'])) { | |
| 307 // Older release history XML file without supported or recommended. | |
| 308 $supported_majors[] = $available[$project]['default_major']; | |
| 309 } | |
| 310 | |
| 311 if (in_array($existing_major, $supported_majors)) { | |
| 312 // Still supported, stay at the current major version. | |
| 313 $target_major = $existing_major; | |
| 314 } | |
| 315 elseif (isset($available[$project]['recommended_major'])) { | |
| 316 // Since 'recommended_major' is defined, we know this is the new XML | |
| 317 // format. Therefore, we know the current release is unsupported since | |
| 318 // its major version was not in the 'supported_majors' list. We should | |
| 319 // find the best release from the recommended major version. | |
| 320 $target_major = $available[$project]['recommended_major']; | |
| 321 $projects[$project]['status'] = UPDATE_NOT_SUPPORTED; | |
| 322 } | |
| 323 elseif (isset($available[$project]['default_major'])) { | |
| 324 // Older release history XML file without recommended, so recommend | |
| 325 // the currently defined "default_major" version. | |
| 326 $target_major = $available[$project]['default_major']; | |
| 327 } | |
| 328 else { | |
| 329 // Malformed XML file? Stick with the current version. | |
| 330 $target_major = $existing_major; | |
| 331 } | |
| 332 | |
| 333 // Make sure we never tell the admin to downgrade. If we recommended an | |
| 334 // earlier version than the one they're running, they'd face an | |
| 335 // impossible data migration problem, since Drupal never supports a DB | |
| 336 // downgrade path. In the unfortunate case that what they're running is | |
| 337 // unsupported, and there's nothing newer for them to upgrade to, we | |
| 338 // can't print out a "Recommended version", but just have to tell them | |
| 339 // what they have is unsupported and let them figure it out. | |
| 340 $target_major = max($existing_major, $target_major); | |
| 341 | |
| 342 $version_patch_changed = ''; | |
| 343 $patch = ''; | |
| 344 | |
| 345 // Defend ourselves from XML history files that contain no releases. | |
| 346 if (empty($available[$project]['releases'])) { | |
| 347 $projects[$project]['status'] = UPDATE_UNKNOWN; | |
| 348 $projects[$project]['reason'] = t('No available releases found'); | |
| 349 continue; | |
| 350 } | |
| 351 foreach ($available[$project]['releases'] as $version => $release) { | |
| 352 // First, if this is the existing release, check a few conditions. | |
| 353 if ($projects[$project]['existing_version'] == $version) { | |
| 354 if (isset($release['terms']['Release type']) && | |
| 355 in_array('Insecure', $release['terms']['Release type'])) { | |
| 356 $projects[$project]['status'] = UPDATE_NOT_SECURE; | |
| 357 } | |
| 358 elseif ($release['status'] == 'unpublished') { | |
| 359 $projects[$project]['status'] = UPDATE_REVOKED; | |
| 360 if (empty($projects[$project]['extra'])) { | |
| 361 $projects[$project]['extra'] = array(); | |
| 362 } | |
| 363 $projects[$project]['extra'][] = array( | |
| 364 'class' => 'release-revoked', | |
| 365 'label' => t('Release revoked'), | |
| 366 'data' => t('Your currently installed release has been revoked, and is no longer available for download. Disabling everything included in this release or upgrading is strongly recommended!'), | |
| 367 ); | |
| 368 } | |
| 369 elseif (isset($release['terms']['Release type']) && | |
| 370 in_array('Unsupported', $release['terms']['Release type'])) { | |
| 371 $projects[$project]['status'] = UPDATE_NOT_SUPPORTED; | |
| 372 if (empty($projects[$project]['extra'])) { | |
| 373 $projects[$project]['extra'] = array(); | |
| 374 } | |
| 375 $projects[$project]['extra'][] = array( | |
| 376 'class' => 'release-not-supported', | |
| 377 'label' => t('Release not supported'), | |
| 378 'data' => t('Your currently installed release is now unsupported, and is no longer available for download. Disabling everything included in this release or upgrading is strongly recommended!'), | |
| 379 ); | |
| 380 } | |
| 381 } | |
| 382 | |
| 383 // Otherwise, ignore unpublished, insecure, or unsupported releases. | |
| 384 if ($release['status'] == 'unpublished' || | |
| 385 (isset($release['terms']['Release type']) && | |
| 386 (in_array('Insecure', $release['terms']['Release type']) || | |
| 387 in_array('Unsupported', $release['terms']['Release type'])))) { | |
| 388 continue; | |
| 389 } | |
| 390 | |
| 391 // See if this is a higher major version than our target and yet still | |
| 392 // supported. If so, record it as an "Also available" release. | |
| 393 if ($release['version_major'] > $target_major) { | |
| 394 if (in_array($release['version_major'], $supported_majors)) { | |
| 395 if (!isset($available[$project]['also'])) { | |
| 396 $available[$project]['also'] = array(); | |
| 397 } | |
| 398 if (!isset($available[$project]['also'][$release['version_major']])) { | |
| 399 $available[$project]['also'][$release['version_major']] = $version; | |
| 400 } | |
| 401 } | |
| 402 // Otherwise, this release can't matter to us, since it's neither | |
| 403 // from the release series we're currently using nor the recommended | |
| 404 // release. We don't even care about security updates for this | |
| 405 // branch, since if a project maintainer puts out a security release | |
| 406 // at a higher major version and not at the lower major version, | |
| 407 // they must remove the lower version from the supported major | |
| 408 // versions at the same time, in which case we won't hit this code. | |
| 409 continue; | |
| 410 } | |
| 411 | |
| 412 // Look for the 'latest version' if we haven't found it yet. Latest is | |
| 413 // defined as the most recent version for the target major version. | |
| 414 if (!isset($available[$project]['latest_version']) | |
| 415 && $release['version_major'] == $target_major) { | |
| 416 $available[$project]['latest_version'] = $version; | |
| 417 } | |
| 418 | |
| 419 // Look for the development snapshot release for this branch. | |
| 420 if (!isset($available[$project]['dev_version']) | |
| 421 && $release['version_major'] == $target_major | |
| 422 && isset($release['version_extra']) | |
| 423 && $release['version_extra'] == 'dev') { | |
| 424 $available[$project]['dev_version'] = $version; | |
| 425 } | |
| 426 | |
| 427 // Look for the 'recommended' version if we haven't found it yet (see | |
| 428 // phpdoc at the top of this function for the definition). | |
| 429 if (!isset($available[$project]['recommended']) | |
| 430 && $release['version_major'] == $target_major | |
| 431 && isset($release['version_patch'])) { | |
| 432 if ($patch != $release['version_patch']) { | |
| 433 $patch = $release['version_patch']; | |
| 434 $version_patch_changed = $release['version']; | |
| 435 } | |
| 436 if (empty($release['version_extra']) && $patch == $release['version_patch']) { | |
| 437 $available[$project]['recommended'] = $version_patch_changed; | |
| 438 } | |
| 439 } | |
| 440 | |
| 441 // Stop searching once we hit the currently installed version. | |
| 442 if ($projects[$project]['existing_version'] == $version) { | |
| 443 break; | |
| 444 } | |
| 445 | |
| 446 // If we're running a dev snapshot and have a timestamp, stop | |
| 447 // searching for security updates once we hit an official release | |
| 448 // older than what we've got. Allow 100 seconds of leeway to handle | |
| 449 // differences between the datestamp in the .info file and the | |
| 450 // timestamp of the tarball itself (which are usually off by 1 or 2 | |
| 451 // seconds) so that we don't flag that as a new release. | |
| 452 if ($projects[$project]['install_type'] == 'dev') { | |
| 453 if (empty($projects[$project]['datestamp'])) { | |
| 454 // We don't have current timestamp info, so we can't know. | |
| 455 continue; | |
| 456 } | |
| 457 elseif (isset($release['date']) && ($projects[$project]['datestamp'] + 100 > $release['date'])) { | |
| 458 // We're newer than this, so we can skip it. | |
| 459 continue; | |
| 460 } | |
| 461 } | |
| 462 | |
| 463 // See if this release is a security update. | |
| 464 if (isset($release['terms']['Release type']) | |
| 465 && in_array('Security update', $release['terms']['Release type'])) { | |
| 466 $projects[$project]['security updates'][] = $release; | |
| 467 } | |
| 468 } | |
| 469 | |
| 470 // If we were unable to find a recommended version, then make the latest | |
| 471 // version the recommended version if possible. | |
| 472 if (!isset($available[$project]['recommended']) && isset($available[$project]['latest_version'])) { | |
| 473 $available[$project]['recommended'] = $available[$project]['latest_version']; | |
| 474 } | |
| 475 | |
| 476 // Stash the info about available releases into our $projects array. | |
| 477 $projects[$project] += $available[$project]; | |
| 478 | |
| 479 // | |
| 480 // Check to see if we need an update or not. | |
| 481 // | |
| 482 | |
| 483 if (!empty($projects[$project]['security updates'])) { | |
| 484 // If we found security updates, that always trumps any other status. | |
| 485 $projects[$project]['status'] = UPDATE_NOT_SECURE; | |
| 486 } | |
| 487 | |
| 488 if (isset($projects[$project]['status'])) { | |
| 489 // If we already know the status, we're done. | |
| 490 continue; | |
| 491 } | |
| 492 | |
| 493 // If we don't know what to recommend, there's nothing we can report. | |
| 494 // Bail out early. | |
| 495 if (!isset($projects[$project]['recommended'])) { | |
| 496 $projects[$project]['status'] = UPDATE_UNKNOWN; | |
| 497 $projects[$project]['reason'] = t('No available releases found'); | |
| 498 continue; | |
| 499 } | |
| 500 | |
| 501 // If we're running a dev snapshot, compare the date of the dev snapshot | |
| 502 // with the latest official version, and record the absolute latest in | |
| 503 // 'latest_dev' so we can correctly decide if there's a newer release | |
| 504 // than our current snapshot. | |
| 505 if ($projects[$project]['install_type'] == 'dev') { | |
| 506 if (isset($available[$project]['dev_version']) && $available[$project]['releases'][$available[$project]['dev_version']]['date'] > $available[$project]['releases'][$available[$project]['latest_version']]['date']) { | |
| 507 $projects[$project]['latest_dev'] = $available[$project]['dev_version']; | |
| 508 } | |
| 509 else { | |
| 510 $projects[$project]['latest_dev'] = $available[$project]['latest_version']; | |
| 511 } | |
| 512 } | |
| 513 | |
| 514 // Figure out the status, based on what we've seen and the install type. | |
| 515 switch ($projects[$project]['install_type']) { | |
| 516 case 'official': | |
| 517 if ($projects[$project]['existing_version'] == $projects[$project]['recommended'] || $projects[$project]['existing_version'] == $projects[$project]['latest_version']) { | |
| 518 $projects[$project]['status'] = UPDATE_CURRENT; | |
| 519 } | |
| 520 else { | |
| 521 $projects[$project]['status'] = UPDATE_NOT_CURRENT; | |
| 522 } | |
| 523 break; | |
| 524 | |
| 525 case 'dev': | |
| 526 $latest = $available[$project]['releases'][$projects[$project]['latest_dev']]; | |
| 527 if (empty($projects[$project]['datestamp'])) { | |
| 528 $projects[$project]['status'] = UPDATE_NOT_CHECKED; | |
| 529 $projects[$project]['reason'] = t('Unknown release date'); | |
| 530 } | |
| 531 elseif (($projects[$project]['datestamp'] + 100 > $latest['date'])) { | |
| 532 $projects[$project]['status'] = UPDATE_CURRENT; | |
| 533 } | |
| 534 else { | |
| 535 $projects[$project]['status'] = UPDATE_NOT_CURRENT; | |
| 536 } | |
| 537 break; | |
| 538 | |
| 539 default: | |
| 540 $projects[$project]['status'] = UPDATE_UNKNOWN; | |
| 541 $projects[$project]['reason'] = t('Invalid info'); | |
| 542 } | |
| 543 } | |
| 544 else { | |
| 545 $projects[$project]['status'] = UPDATE_UNKNOWN; | |
| 546 $projects[$project]['reason'] = t('No available releases found'); | |
| 547 } | |
| 548 } | |
| 549 // Give other modules a chance to alter the status (for example, to allow a | |
| 550 // contrib module to provide fine-grained settings to ignore specific | |
| 551 // projects or releases). | |
| 552 drupal_alter('update_status', $projects); | |
| 553 | |
| 554 // Set the projects array into the cache table. | |
| 555 cache_set('update_project_data', $projects, 'cache_update', time() + 3600); | |
| 556 return $projects; | |
| 557 } | |
| 558 | |
| 559 /** | |
| 560 * Retrieve data from {cache_update} or empty the cache when necessary. | |
| 561 * | |
| 562 * Two very expensive arrays computed by this module are the list of all | |
| 563 * installed modules and themes (and .info data, project associations, etc), | |
| 564 * and the current status of the site relative to the currently available | |
| 565 * releases. These two arrays are cached in the {cache_update} table and used | |
| 566 * whenever possible. The cache is cleared whenever the administrator visits | |
| 567 * the status report, available updates report, or the module or theme | |
| 568 * administration pages, since we should always recompute the most current | |
| 569 * values on any of those pages. | |
| 570 * | |
| 571 * @param $cid | |
| 572 * The cache id of data to return from the cache. Valid options are | |
| 573 * 'update_project_data' and 'update_project_projects'. | |
| 574 * | |
| 575 * @return | |
| 576 * The cached value of the $projects array generated by | |
| 577 * update_calculate_project_data() or update_get_projects(), or an empty | |
| 578 * array when the cache is cleared. | |
| 579 */ | |
| 580 function update_project_cache($cid) { | |
| 581 $projects = array(); | |
| 582 | |
| 583 // In some cases, we must clear the cache. Rather than do so on a time | |
| 584 // basis, we check for specific paths. | |
| 585 $q = $_GET['q']; | |
| 586 $paths = array('admin/build/modules', 'admin/build/themes', 'admin/reports', 'admin/reports/updates', 'admin/reports/status', 'admin/reports/updates/check'); | |
| 587 if (in_array($q, $paths)) { | |
| 588 cache_clear_all($cid, 'cache_update'); | |
| 589 } | |
| 590 else { | |
| 591 $cache = cache_get($cid, 'cache_update'); | |
| 592 if (!empty($cache->data) && $cache->expire > time()) { | |
| 593 $projects = $cache->data; | |
| 594 } | |
| 595 } | |
| 596 return $projects; | |
| 597 } |
