private function StatusInfoDrush::calculateProjectUpdateStatus

8.0.x StatusInfoDrush.php private StatusInfoDrush::calculateProjectUpdateStatus($project_release_info, &$project_data)
7.x StatusInfoDrush.php private StatusInfoDrush::calculateProjectUpdateStatus($project_release_info, &$project_data)
master StatusInfoDrush.php private StatusInfoDrush::calculateProjectUpdateStatus($project_release_info, &$project_data)

Obtain the update status of a project and the recommended release.

This is a stripped down version of update_calculate_project_status(). That function has the same logic in Drupal 6,7,8. Note: in Drupal 6 this is part of update_calculate_project_data().

See also

update_calculate_project_status().

1 call to StatusInfoDrush::calculateProjectUpdateStatus()
StatusInfoDrush::calculateUpdateStatus in lib/Drush/UpdateService/StatusInfoDrush.php
Calculates update status for given projects.

File

lib/Drush/UpdateService/StatusInfoDrush.php, line 199
Implementation of 'drush' update_status engine for any Drupal version.

Namespace

Drush\UpdateService

Class

StatusInfoDrush

Code

private function calculateProjectUpdateStatus($project_release_info, &$project_data) {
  $available = $project_release_info->getInfo();

  /**
   * Here starts the code adapted from update_calculate_project_status().
   * Line 492 in Drupal 7.
   *
   * Changes are:
   *   - Use DRUSH_UPDATESTATUS_* constants instead of DRUSH_UPDATESTATUS_*
   *   - Remove error conditions we already handle
   *   - Remove presentation code ('extra' and 'reason' keys in $project_data)
   *   - Remove "also available" information.
   */

  // Figure out the target major version.
  $existing_major = $project_data['existing_major'];
  $supported_majors = array();
  if (isset($available['supported_majors'])) {
    $supported_majors = explode(',', $available['supported_majors']);
  }
  elseif (isset($available['default_major'])) {
    // Older release history XML file without supported or recommended.
    $supported_majors[] = $available['default_major'];
  }

  if (in_array($existing_major, $supported_majors)) {
    // Still supported, stay at the current major version.
    $target_major = $existing_major;
  }
  elseif (isset($available['recommended_major'])) {
    // Since 'recommended_major' is defined, we know this is the new XML
    // format. Therefore, we know the current release is unsupported since
    // its major version was not in the 'supported_majors' list. We should
    // find the best release from the recommended major version.
    $target_major = $available['recommended_major'];
    $project_data['status'] = DRUSH_UPDATESTATUS_NOT_SUPPORTED;
  }
  elseif (isset($available['default_major'])) {
    // Older release history XML file without recommended, so recommend
    // the currently defined "default_major" version.
    $target_major = $available['default_major'];
  }
  else {
    // Malformed XML file? Stick with the current version.
    $target_major = $existing_major;
  }

  // Make sure we never tell the admin to downgrade. If we recommended an
  // earlier version than the one they're running, they'd face an
  // impossible data migration problem, since Drupal never supports a DB
  // downgrade path. In the unfortunate case that what they're running is
  // unsupported, and there's nothing newer for them to upgrade to, we
  // can't print out a "Recommended version", but just have to tell them
  // what they have is unsupported and let them figure it out.
  $target_major = max($existing_major, $target_major);

  $release_patch_changed = '';
  $patch = '';

  foreach ($available['releases'] as $version => $release) {
    // First, if this is the existing release, check a few conditions.
    if ($project_data['existing_version'] === $version) {
      if (isset($release['terms']['Release type']) && in_array('Insecure', $release['terms']['Release type'])) {
        $project_data['status'] = DRUSH_UPDATESTATUS_NOT_SECURE;
      }
      elseif ($release['status'] == 'unpublished') {
        $project_data['status'] = DRUSH_UPDATESTATUS_REVOKED;
      }
      elseif (isset($release['terms']['Release type']) && in_array('Unsupported', $release['terms']['Release type'])) {
        $project_data['status'] = DRUSH_UPDATESTATUS_NOT_SUPPORTED;
      }
    }

    // Otherwise, ignore unpublished, insecure, or unsupported releases.
    if ($release['status'] == 'unpublished' || (isset($release['terms']['Release type']) && (in_array('Insecure', $release['terms']['Release type']) || in_array('Unsupported', $release['terms']['Release type'])))) {
      continue;
    }

    // See if this is a higher major version than our target and discard it.
    // Note: at this point Drupal record it as an "Also available" release.
    if (isset($release['version_major']) && $release['version_major'] > $target_major) {
      continue;
    }

    // Look for the 'latest version' if we haven't found it yet. Latest is
    // defined as the most recent version for the target major version.
    if (!isset($project_data['latest_version']) && $release['version_major'] == $target_major) {
      $project_data['latest_version'] = $version;
      $project_data['releases'][$version] = $release;
    }

    // Look for the development snapshot release for this branch.
    if (!isset($project_data['dev_version']) && $release['version_major'] == $target_major && isset($release['version_extra']) && $release['version_extra'] == 'dev') {
      $project_data['dev_version'] = $version;
      $project_data['releases'][$version] = $release;
    }

    // Look for the 'recommended' version if we haven't found it yet (see
    // phpdoc at the top of this function for the definition).
    if (!isset($project_data['recommended']) && $release['version_major'] == $target_major && isset($release['version_patch'])) {
      if ($patch != $release['version_patch']) {
        $patch = $release['version_patch'];
        $release_patch_changed = $release;
      }
      if (empty($release['version_extra']) && $patch == $release['version_patch']) {
        $project_data['recommended'] = $release_patch_changed['version'];
        $project_data['releases'][$release_patch_changed['version']] = $release_patch_changed;
      }
    }

    // Stop searching once we hit the currently installed version.
    if ($project_data['existing_version'] === $version) {
      break;
    }

    // If we're running a dev snapshot and have a timestamp, stop
    // searching for security updates once we hit an official release
    // older than what we've got. Allow 100 seconds of leeway to handle
    // differences between the datestamp in the .info file and the
    // timestamp of the tarball itself (which are usually off by 1 or 2
    // seconds) so that we don't flag that as a new release.
    if ($project_data['install_type'] == 'dev') {
      if (empty($project_data['datestamp'])) {
        // We don't have current timestamp info, so we can't know.
        continue;
      }
      elseif (isset($release['date']) && ($project_data['datestamp'] + 100 > $release['date'])) {
        // We're newer than this, so we can skip it.
        continue;
      }
    }

    // See if this release is a security update.
    if (isset($release['terms']['Release type']) && in_array('Security update', $release['terms']['Release type'])) {
      $project_data['security updates'][] = $release;
    }
  }

  // If we were unable to find a recommended version, then make the latest
  // version the recommended version if possible.
  if (!isset($project_data['recommended']) && isset($project_data['latest_version'])) {
    $project_data['recommended'] = $project_data['latest_version'];
  }

  //
  // Check to see if we need an update or not.
  //

  if (!empty($project_data['security updates'])) {
    // If we found security updates, that always trumps any other status.
    $project_data['status'] = DRUSH_UPDATESTATUS_NOT_SECURE;
  }

  if (isset($project_data['status'])) {
    // If we already know the status, we're done.
    return;
  }

  // If we don't know what to recommend, there's nothing we can report.
  // Bail out early.
  if (!isset($project_data['recommended'])) {
    $project_data['status'] = DRUSH_UPDATESTATUS_UNKNOWN;
    $project_data['reason'] = t('No available releases found');
    return;
  }

  // If we're running a dev snapshot, compare the date of the dev snapshot
  // with the latest official version, and record the absolute latest in
  // 'latest_dev' so we can correctly decide if there's a newer release
  // than our current snapshot.
  if ($project_data['install_type'] == 'dev') {
    if (isset($project_data['dev_version']) && $available['releases'][$project_data['dev_version']]['date'] > $available['releases'][$project_data['latest_version']]['date']) {
      $project_data['latest_dev'] = $project_data['dev_version'];
    }
    else {
      $project_data['latest_dev'] = $project_data['latest_version'];
    }
  }

  // Figure out the status, based on what we've seen and the install type.
  switch ($project_data['install_type']) {
    case 'official':
      if ($project_data['existing_version'] === $project_data['recommended'] || $project_data['existing_version'] === $project_data['latest_version']) {
        $project_data['status'] = DRUSH_UPDATESTATUS_CURRENT;
      }
      else {
        $project_data['status'] = DRUSH_UPDATESTATUS_NOT_CURRENT;
      }
      break;

    case 'dev':
      $latest = $available['releases'][$project_data['latest_dev']];
      if (empty($project_data['datestamp'])) {
        $project_data['status'] = DRUSH_UPDATESTATUS_NOT_CHECKED;
      }
      elseif (($project_data['datestamp'] + 100 > $latest['date'])) {
        $project_data['status'] = DRUSH_UPDATESTATUS_CURRENT;
      }
      else {
        $project_data['status'] = DRUSH_UPDATESTATUS_NOT_CURRENT;
      }
      break;

    default:
      $project_data['status'] = DRUSH_UPDATESTATUS_UNKNOWN;
  }
}