5 * Drush release info engine for update.drupal.org and compatible services.
7 * This engine does connect directly to the update service. It doesn't depend
8 * on a bootstrapped site.
11 namespace Drush\UpdateService;
13 use Drush\Log\LogLevel;
16 * Release info engine class.
19 const DEFAULT_URL = 'https://updates.drupal.org/release-history';
21 // Cache release xml files for 24h by default.
22 const CACHE_LIFETIME = 86400;
25 private $engine_config;
30 public function __construct($type, $engine, $config) {
31 $this->engine_type = $type;
32 $this->engine = $engine;
34 if (is_null($config)) {
38 'cache-duration' => drush_get_option('cache-duration-releasexml', self::CACHE_LIFETIME),
40 $this->engine_config = $config;
41 $this->cache = array();
45 * Returns configured cache duration.
47 public function getCacheDuration() {
48 return $this->engine_config['cache-duration'];
52 * Returns a project's release info from the update service.
54 * @param array $request
57 * @param bool $refresh
58 * Whether to discard cached object.
60 * @return \Drush\UpdateService\Project
62 public function get($request, $refresh = FALSE) {
63 if ($refresh || !isset($this->cache[$request['name']])) {
64 $project_release_info = Project::getInstance($request, $this->getCacheDuration());
65 if ($project_release_info && !$project_release_info->isValid()) {
66 $project_release_info = FALSE;
68 $this->cache[$request['name']] = $project_release_info;
70 return $this->cache[$request['name']];
74 * Delete cached update service file of a project.
76 * @param array $request
79 public function clearCached(array $request) {
80 if (isset($this->cache[$request['name']])) {
81 unset($this->cache[$request['name']]);
83 $url = Project::buildFetchUrl($request);
84 $cache_file = drush_download_file_name($url);
85 if (file_exists($cache_file)) {
91 * Select the most appropriate release for a project, based on a strategy.
93 * @param Array &$request
95 * The array will be expanded with the project type.
96 * @param String $restrict_to
98 * 'dev': Forces choosing a -dev release.
99 * 'version': Forces choosing a point release.
100 * '': No restriction.
102 * @param String $select
103 * Strategy for selecting a release, should be one of:
104 * - auto: Try to select the latest release, if none found allow the user
106 * - always: Force the user to choose a release.
107 * - never: Try to select the latest release, if none found then fail.
108 * - ignore: Ignore and return NULL.
109 * If no supported release is found, allow to ask the user to choose one.
110 * @param Boolean $all
111 * In case $select = TRUE this indicates that all available releases will be
112 * offered the user to choose.
115 * The selected release.
117 public function selectReleaseBasedOnStrategy($request, $restrict_to = '', $select = 'never', $all = FALSE, $version = NULL) {
118 if (!in_array($select, array('auto', 'never', 'always', 'ignore'))) {
119 return drush_set_error('DRUSH_PM_UNKNOWN_SELECT_STRATEGY', dt("Error: select strategy must be one of: auto, never, always, ignore", array()));
122 $project_release_info = $this->get($request);
123 if (!$project_release_info) {
127 if ($select != 'always') {
128 if (isset($request['version'])) {
129 $release = $project_release_info->getSpecificRelease($request['version']);
130 if ($release === FALSE) {
131 return drush_set_error('DRUSH_PM_COULD_NOT_FIND_VERSION', dt("Could not locate !project version !version.", array(
132 '!project' => $request['name'],
133 '!version' => $request['version'],
137 if ($restrict_to == 'dev') {
138 // If you specified a specific release AND --dev, that is either
139 // redundant (okay), or contradictory (error).
140 if (!empty($release)) {
141 if ($release['version_extra'] != 'dev') {
142 return drush_set_error('DRUSH_PM_COULD_NOT_FIND_VERSION', dt("You requested both --dev and !project version !version, which is not a '-dev' release.", array(
143 '!project' => $request['name'],
144 '!version' => $request['version'],
149 $release = $project_release_info->getDevRelease();
150 if ($release === FALSE) {
151 return drush_set_error('DRUSH_PM_NO_DEV_RELEASE', dt('There is no development release for project !project.', array('!project' => $request['name'])));
155 // If there was no specific release requested, try to identify the most appropriate release.
156 if (empty($release)) {
157 $release = $project_release_info->getRecommendedOrSupportedRelease();
163 $message = dt('There are no stable releases for project !project.', array('!project' => $request['name']));
164 if ($select == 'never') {
165 return drush_set_error('DRUSH_PM_NO_STABLE_RELEASE', $message);
167 drush_log($message, LogLevel::WARNING);
168 if ($select == 'ignore') {
174 // At this point the only chance is to ask the user to choose a release.
175 if ($restrict_to == 'dev') {
184 $releases = $project_release_info->filterReleases($filter, $version);
186 // Special checking: Drupal 6 is EOL, so there are no stable
187 // releases for ANY contrib project. In this case, we'll default
188 // to the best release, unless the user specified --select.
189 $version_major = drush_drupal_major_version();
190 if (($select != 'always') && ($version_major < 7)) {
191 $bestRelease = Project::getBestRelease($releases);
192 if (!empty($bestRelease)) {
193 $message = dt('Drupal !major has reached EOL, so there are no stable releases for any contrib projects. Selected the best release, !project.', array('!major' => $version_major, '!project' => $bestRelease['name']));
194 drush_log($message, LogLevel::WARNING);
200 foreach($releases as $release) {
201 $options[$release['version']] = array($release['version'], '-', gmdate('Y-M-d', $release['date']), '-', implode(', ', $release['release_status']));
203 $choice = drush_choice($options, dt('Choose one of the available releases for !project:', array('!project' => $request['name'])));
205 return drush_user_abort();
208 return $releases[$choice];
212 * Check if a project is available in the update service.
214 * Optionally check for consistency by comparing given project type and
215 * the type obtained from the update service.
217 * @param array $request
219 * @param string $type
220 * Optional. If provided, will do a consistent check of the project type.
223 * True if the project exists and type matches.
225 public function checkProject($request, $type = NULL) {
226 $project_release_info = $this->get($request);
227 if (!$project_release_info) {
231 if ($project_release_info->getType() != $type) {