? .DS_Store
? head.db
? updates-395474-54.patch
? updates-395474-86.patch
? modules/.DS_Store
? modules/update/.DS_Store
? sites/all/.DS_Store
? sites/all/modules/permission_select
? sites/default/files
? sites/default/settings.php
Index: modules/update/update.admin.inc
===================================================================
RCS file: modules/update/update.admin.inc
diff -N modules/update/update.admin.inc
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ modules/update/update.admin.inc 7 Jul 2009 07:17:52 -0000
@@ -0,0 +1,282 @@
+ 'item',
+ '#title' => t('Update log'),
+ '#markup' => theme('item_list', $results['messages']),
+ );
+ return $form;
+ }
+
+ if (!isset($form_state['values'])) {
+ $form['projects'] = array();
+ // First step.
+ $form['#theme'] = 'update_available_updates_form';
+ if ($available = update_get_available(TRUE)) {
+ module_load_include('inc', 'update', 'update.compare');
+ $project_data = update_calculate_project_data($available);
+ foreach ($project_data as $name => $project) {
+ // Filter out projects which are dev versions, updated or core
+ if (($project['install_type'] != 'dev') && ($project['project_type'] != 'core')) {
+ switch ($project['status']) {
+ case UPDATE_NOT_SECURE:
+ case UPDATE_REVOKED:
+ $type = 'security';
+ break;
+ case UPDATE_NOT_SUPPORTED:
+ $type = 'unsupported';
+ break;
+ case UPDATE_UNKNOWN:
+ case UPDATE_NOT_FETCHED:
+ case UPDATE_NOT_CHECKED:
+ case UPDATE_NOT_CURRENT:
+ $type = 'recommended';
+ break;
+ }
+ $project['type'] = $type;
+ $project['title'] = l(check_plain($project['title']), $project['link']);
+ if ($project['project_type'] == 'theme') {
+ $project['title'] .= t(' (Theme)');
+ }
+ if ($type == 'unsupported') {
+ $project['title'] .= t(' (Unsupported)');
+ }
+ elseif ($type == 'security') {
+ $project['title'] .= t(' (Security Update)');
+ }
+ $project['recommended_version'] = l($project['recommended'], $project['releases'][$project['recommended']]['release_link']);
+ $form['projects'][$name] = array(
+ '#type' => 'checkbox',
+ '#project' => $project,
+ '#weight' => ($type == 'recommended' ? 0 : -1),
+ );
+
+ }
+ }
+ }
+ else {
+ $form['message'] = array(
+ '#type' => 'item',
+ '#markup' => t('There was a problem getting update information. Please try again later.'),
+ );
+ return $form;
+ }
+
+ if (!count($form['projects'])) {
+ $form['message'] = array(
+ '#type' => 'item',
+ '#markup' => t('All of your projects are up to date.'),
+ );
+ return $form;
+ }
+ $form['projects']['#tree'] = TRUE;
+ $form['submit'] = array(
+ '#type' => 'submit',
+ '#value' => t('Continue'),
+ '#weight' => 100,
+ );
+ }
+ else if (is_array($form_state['values']) && array_filter($form_state['values']['projects'])) {
+ $form['#attached_js'][] = drupal_get_path('module', 'update') . '/update.js';
+ // Get all the available ways to transfer files.
+ $available_backends = module_invoke_all('filetransfer_backends');
+ if (!count($available_backends)) {
+ // @TODO: Clean up this error handling
+ drupal_set_message(t('Unable to continue, not available methods of file transfer'), 'error');
+ return array();
+ }
+
+ $form['information']['#weight'] = -100;
+ $form['information']['backup_header'] = array(
+ '#prefix' => '
',
+ '#value' => t('Step 1: Backup your site'),
+ '#suffix' => '
',
+ );
+
+ $form['information']['backup_message'] = array(
+ '#prefix' => '',
+ '#value' => t('We do not currently have a web based backup tool. Learn more about how to take a backup.', array('@backup_url' => url('http://drupal.org/node/22281'))),
+ '#suffix' => '
',
+ );
+
+ $form['information']['main_header'] = array(
+ '#prefix' => '',
+ '#value' => t('Step 2: Provide your server connection details'),
+ '#suffix' => '
',
+ );
+
+ $form['projects'] = array (
+ '#type' => 'value',
+ '#value' => array_keys(array_filter($form_state['values']['projects'])),
+ );
+
+ uasort($available_backends, 'drupal_sort_weight');
+
+ // Decide on a default backend.
+ if (isset($form_state['values']['connection_settings']['update_filetransfer_default'])) {
+ $update_filetransfer_default = $form_state['values']['connection_settings']['update_filetransfer_default'];
+ }
+ elseif ($update_filetransfer_default = variable_get('update_filetransfer_default', NULL));
+ else {
+ $update_filetransfer_default = key($available_backends);
+ }
+
+ $form['connection_settings']['#tree'] = TRUE;
+ $form['connection_settings']['update_filetransfer_default'] = array(
+ '#type' => 'select',
+ '#title' => t('Connection method'),
+ '#default_value' => array($update_filetransfer_default),
+ );
+
+ // Build a hidden fieldset for each one.
+ foreach ($available_backends as $name => $backend) {
+ $form['connection_settings']['update_filetransfer_default']['#options'][$name] = $backend['title'];
+ $form['connection_settings'][$name] = array (
+ '#type' => 'fieldset',
+ '#attributes' => array('class' => "filetransfer-$name filetransfer"),
+ '#title' => t('@backend connection settings', array('@backend' => $backend['title'])),
+ );
+ $current_settings = variable_get("update_filetransfer_connection_settings_" . $name, array());
+ $form['connection_settings'][$name] += system_get_filetransfer_settings_form($name, $current_settings);
+ }
+
+ $form['submit'] = array(
+ '#name' => 'process_updates',
+ '#type' => 'submit',
+ '#value' => (variable_get('site_offline', FALSE) == FALSE) ? t('Put site into maintenance mode and install updates') : t('Install updates'),
+ '#weight' => 100,
+ );
+ }
+
+ return $form;
+}
+
+function update_update_form_validate($form, &$form_state) {
+ if (isset($form_state['values']['connection_settings'])) {
+ $filetransfer_backend_to_test = $form_state['values']['connection_settings']['update_filetransfer_default'];
+ $connection_settings = $form_state['values']['connection_settings'][$filetransfer_backend_to_test];
+ $available_backends = module_invoke_all('filetransfer_backends');
+ $filetransfer_class = $available_backends[$filetransfer_backend_to_test]['class'];
+ $filetransfer = call_user_func_array(array($filetransfer_class, 'factory'), array(DRUPAL_ROOT, $connection_settings));
+ try {
+ $filetransfer->connect();
+ }
+ catch(Exception $e) {
+ form_set_error('connection_settings', $e->getMessage());
+ }
+ }
+}
+
+function update_update_form_submit($form, &$form_state) {
+ // We always want to rebuild unless we are done.
+ $form_state['rebuild'] = TRUE;
+
+ if ($form_state['clicked_button']['#name'] == 'process_updates') {
+ // Save the connection settings to the DB.
+ $filetransfer_backend_to_use = $form_state['values']['connection_settings']['update_filetransfer_default'];
+ $connection_settings = $form_state['values']['connection_settings'][$filetransfer_backend_to_use];
+
+ // This is a hack, perhaps we should add an attribute to non-stored fields?
+ // For SSH keys we wouldn't want to use a password field for instance.
+ $connection_settings_to_save = array();
+ foreach ($connection_settings as $key => $value) {
+ if ($form['connection_settings'][$filetransfer_backend_to_use][$key]['#type'] != 'password') {
+ $connection_settings_to_save[$key] = $value;
+ }
+ }
+ // Set this one as the default update method.
+ variable_set('update_filetransfer_default', $filetransfer_backend_to_use);
+ // Save the connection settings minus the password
+ variable_set("update_filetransfer_connection_settings_" . $filetransfer_backend_to_use, $connection_settings_to_save);
+
+ $operations = array();
+ foreach ($form_state['values']['projects'] as $project) {
+ // HACK: Bad workflow here... don't know how to determine what type of project this is.
+ $project_type = UPDATE_EXTENSION_TYPE_MODULE;
+ // Put this in the begining (download everything first)
+ $operations['1_get_' . $project] = array('update_get_extension', array($project));
+ // Put these on the end
+ $operations['2_put_' . $project] = array(
+ 'update_copy_extension',
+ array(
+ $project,
+ $project_type,
+ update_get_default_filetransfer($connection_settings)
+ ),
+ );
+ $operations['3_install_' . $project] = array('update_install_extension', array($project));
+ }
+ ksort($operations);
+
+ $batch = array(
+ 'title' => t('Installing updates'),
+ 'init_message' => t('Preparing update operation'),
+ 'operations' => $operations,
+ 'finished' => 'update_batch_finished',
+ );
+ batch_set($batch);
+ }
+}
+
+/**
+ * Theme project status report.
+ *
+ * @ingroup themeable
+ */
+function theme_update_available_updates_form($form) {
+ $last = variable_get('update_last_check', 0);
+ $output = '' . ($last ? t('Last checked: @time ago', array('@time' => format_interval(REQUEST_TIME - $last))) : t('Last checked: never'));
+ $output .= ' (' . l(t('Check manually'), 'admin/reports/updates/check') . ')';
+ $output .= "
\n";
+ if (isset($form['message'])) {
+ $output .= drupal_render($form['message']);
+ return $output;
+ }
+ $rows = array();
+ drupal_add_css(drupal_get_path('module', 'update') . '/update.css');
+ foreach (element_children($form['projects']) as $key) {
+ $rows[] = array(
+ 'class' => $form['projects'][$key]['#project']['type'],
+ 'data' => array(
+ drupal_render($form['projects'][$key]),
+ array(
+ 'class' => 'update-project-name',
+ 'data' => $form['projects'][$key]['#project']['title'],
+ ),
+ $form['projects'][$key]['#project']['existing_version'],
+ l($form['projects'][$key]['#project']['recommended'], $form['projects'][$key]['#project']['releases'][$form['projects'][$key]['#project']['recommended']]['release_link']),
+ ),
+ );
+ //$form['project'][$key];
+ }
+ $output .= theme('table', array(theme('table_select_header_cell'), t('Name'), t('Current Version'), t('Recommended Version')), $rows);
+ $output .= drupal_render_children($form);
+ return $output;
+}
+/*
+ case UPDATE_NOT_SECURE:
+ case UPDATE_REVOKED:
+ $type = 'security';
+ break;
+ case UPDATE_NOT_SUPPORTED:
+ $type = 'unsupported';
+ break;
+ case UPDATE_UNKNOWN:
+ case UPDATE_NOT_FETCHED:
+ case UPDATE_NOT_CHECKED:
+ case UPDATE_NOT_CURRENT:
+ $type = 'recommended';
+*/
\ No newline at end of file
Index: modules/update/update.css
===================================================================
RCS file: /cvs/drupal/drupal/modules/update/update.css,v
retrieving revision 1.5
diff -u -p -r1.5 update.css
--- modules/update/update.css 29 Apr 2009 03:57:21 -0000 1.5
+++ modules/update/update.css 7 Jul 2009 07:17:52 -0000
@@ -1,110 +1,10 @@
-/* $Id: update.css,v 1.5 2009/04/29 03:57:21 webchick Exp $ */
+/* $Id$ */
-.update .project {
- font-weight: bold;
- font-size: 110%;
- padding-left: .25em; /* LTR */
- height: 22px;
-}
-
-.update .version-status {
- float: right; /* LTR */
- padding-right: 10px; /* LTR */
- font-size: 110%;
- height: 20px;
-}
-
-.update .version-status .icon {
- padding-left: .5em; /* LTR */
-}
-
-.update .version-date {
- white-space: nowrap;
-}
-
-.update .info {
- margin: 0;
- padding: 1em 1em .25em 1em;
-}
-
-.update tr td {
- border-top: 1px solid #ccc;
- border-bottom: 1px solid #ccc;
-}
-
-.update tr.error {
+.update tr.security,
+.update tr.unsupported {
background: #fcc;
}
-.update tr.error .version-recommended {
- background: #fdd;
-}
-
-.update tr.ok {
- background: #dfd;
-}
-
-.update tr.warning {
- background: #ffd;
-}
-
-.update tr.warning .version-recommended {
- background: #ffe;
-}
-
-.current-version, .new-version {
- direction: ltr; /* Note: version numbers should always be LTR. */
-}
-
-.update tr.unknown {
- background: #ddd;
-}
-
-table.update,
-.update table.version {
- width: 100%;
- margin-top: .5em;
-}
-
-.update table.version tbody {
- border: none;
-}
-
-.update table.version tr,
-.update table.version td {
- line-height: .9em;
- padding: 0;
- margin: 0;
- border: none;
-}
-
-.update table.version .version-title {
- padding-left: 1em; /* LTR */
- width: 14em;
-}
-
-.update table.version .version-details {
- padding-right: .5em; /* LTR */
-}
-
-.update table.version .version-links {
- text-align: right; /* LTR */
- padding-right: 1em; /* LTR */
-}
-
-.update table.version-security .version-title {
- color: #970F00;
-}
-
-.update table.version-recommended-strong .version-title {
- font-weight: bold;
-}
-
-.update .security-error {
- font-weight: bold;
- color: #970F00;
-}
-
-.update .check-manually {
- padding-left: 1em; /* LTR */
-}
+td.update-project-name {
+ width: 50%;
+}
\ No newline at end of file
Index: modules/update/update.info
===================================================================
RCS file: /cvs/drupal/drupal/modules/update/update.info,v
retrieving revision 1.5
diff -u -p -r1.5 update.info
--- modules/update/update.info 11 Oct 2008 02:33:12 -0000 1.5
+++ modules/update/update.info 7 Jul 2009 07:17:52 -0000
@@ -7,6 +7,7 @@ core = 7.x
files[] = update.module
files[] = update.compare.inc
files[] = update.fetch.inc
-files[] = update.report.inc
+files[] = update.admin.inc
files[] = update.settings.inc
files[] = update.install
+files[] = update.js
Index: modules/update/update.js
===================================================================
RCS file: modules/update/update.js
diff -N modules/update/update.js
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ modules/update/update.js 7 Jul 2009 07:17:52 -0000
@@ -0,0 +1,12 @@
+(function ($) {
+
+Drupal.behaviors.updateFileTransferForm = {
+ attach: function(context) {
+ $('#edit-connection-settings-update-filetransfer-default').change(function() {
+ $('.filetransfer').hide().filter('.filetransfer-' + $(this).val()).show();
+ });
+ $('.filetransfer').hide().filter('.filetransfer-' + $('#edit-connection-settings-update-filetransfer-default').val()).show();
+ }
+}
+
+})(jQuery);
\ No newline at end of file
Index: modules/update/update.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/update/update.module,v
retrieving revision 1.37
diff -u -p -r1.37 update.module
--- modules/update/update.module 8 Jun 2009 05:00:11 -0000 1.37
+++ modules/update/update.module 7 Jul 2009 07:17:52 -0000
@@ -62,6 +62,16 @@ define('UPDATE_NOT_FETCHED', -3);
define('UPDATE_MAX_FETCH_ATTEMPTS', 2);
/**
+ * Used when determining how to act on a given extension when removing / installing
+ */
+define('UPDATE_EXTENSION_TYPE_MODULE', 1);
+
+/**
+ * Used when determining how to act on a given extension when removing / installing
+ */
+define('UPDATE_EXTENSION_TYPE_THEME', 2);
+
+/**
* Implement hook_help().
*/
function update_help($path, $arg) {
@@ -69,8 +79,7 @@ function update_help($path, $arg) {
case 'admin/reports/updates':
global $base_url;
$output = '' . t('Here you can find information about available updates for your installed modules and themes. Note that each module or theme is part of a "project", which may or may not have the same name, and might include multiple modules or themes within it.') . '
';
- $output .= '' . t('To extend the functionality or to change the look of your site, a number of contributed modules and themes are available.', array('@modules' => 'http://drupal.org/project/modules', '@themes' => 'http://drupal.org/project/themes')) . '
';
- $output .= '' . t('Each time Drupal core or a contributed module or theme is updated, it is important that update.php is run.', array('@update-php' => url($base_url . '/update.php', array('external' => TRUE)))) . '
';
+
return $output;
case 'admin/build/themes':
case 'admin/build/modules':
@@ -87,6 +96,12 @@ function update_help($path, $arg) {
}
}
}
+
+ case 'admin/settings/updates/server-settings':
+ $output = '' . t('In order to update / extend your site from the browser you need to configure how to connect to your server.');
+ $output .= t(' If you do not know what to enter on this form, please contact your hosting provider for help.') .'
';
+ return $output;
+ break;
case 'admin/reports/updates/settings':
case 'admin/reports/status':
@@ -125,11 +140,12 @@ function update_help($path, $arg) {
*/
function update_menu() {
$items = array();
-
+
$items['admin/reports/updates'] = array(
'title' => 'Available updates',
'description' => 'Get a status report about available updates for your installed modules and themes.',
- 'page callback' => 'update_status',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('update_update_form'),
'access arguments' => array('administer site configuration'),
'weight' => 10,
);
@@ -155,15 +171,9 @@ function update_menu() {
*/
function update_theme() {
return array(
- 'update_settings' => array(
+ 'update_available_updates_form' => array(
'arguments' => array('form' => NULL),
),
- 'update_report' => array(
- 'arguments' => array('data' => NULL),
- ),
- 'update_version' => array(
- 'arguments' => array('version' => NULL, 'tag' => NULL, 'class' => NULL),
- ),
);
}
@@ -632,3 +642,134 @@ function update_flush_caches() {
/**
* @} End of "defgroup update_status_cache".
*/
+
+function _update_get_latest_version($name) {
+ if ($available = update_get_available(FALSE)) {
+ module_load_include('inc', 'update', 'update.compare');
+ $extension_data = update_calculate_project_data($available);
+ $project = $extension_data[$name];
+ return $project['releases'][$project['latest_version']];
+ }
+}
+
+
+function update_get_file($url) {
+ // Get each of the specified files.
+ $parsed_url = parse_url($url);
+ $local = file_directory_temp() . '/update-cache/' . basename($parsed_url['path']);
+ if (!file_exists(file_directory_temp() . '/update-cache/')) {
+ mkdir(file_directory_temp() . '/update-cache/');
+ }
+ // Check the cache and download the file if needed.
+ if (!file_exists($local)) {
+ // $result->data is the actual contents of the downloaded file. This saves
+ // it into a local file, whose path is stored in $local. $local is stored
+ // relative to the Drupal installation.
+ return system_retrieve_file($url, $local);
+ } else {
+ return $local;
+ }
+}
+
+function update_untar($file) {
+ $extraction_dir = file_directory_temp() . '/update-extraction';
+ if (!file_exists($extraction_dir)) {
+ mkdir($extraction_dir);
+ }
+ $archive_tar = new Archive_Tar($file);
+ return $archive_tar->extract($extraction_dir);
+}
+
+/**
+ * Helper function to determine if it is a module or a theme
+ */
+function _update_get_extension_type($directory) {
+ if (count(file_scan_directory($directory, "/\.module$/")) > 0) {
+ return UPDATE_EXTENSION_TYPE_MODULE;
+ }
+ else {
+ return UPDATE_EXTENSION_TYPE_THEME;
+ }
+}
+
+/**
+ * Batch operations
+ */
+
+function update_get_extension($extension_name, &$context) {
+ if (!isset($context['sandbox']['starting'])) {
+ $context['sandbox']['starting'] = 1;
+ $context['message'] = t('Downloading %extension', array('%extension' => $extension_name));
+ $context['finished'] = 1 / 2;
+ return;
+ }
+ $latest_version = _update_get_latest_version($extension_name);
+ if ($local_cache = update_get_file($latest_version['download_link'])) {
+ watchdog('update', t('Downloaded %extension to %local_cache', array('%extension' => $extension_name, '%local_cache' => $local_cache)));
+ } else {
+ $context['success'] = FALSE;
+ $content['results'][] = t('Failed to download %extension', array('%extension' => $extension_name));
+ }
+
+ $context['finished'] = 1;
+}
+
+function update_copy_extension($extension_name, $extension_type, $filetransfer, &$context) {
+ if (!isset($context['sandbox']['starting'])) {
+ $context['sandbox']['starting'] = 1;
+ $context['message'] = t('Copying %extension to server', array('%extension' => $extension_name));
+ $context['finished'] = .5;
+ return;
+ }
+
+ $latest_version = _update_get_latest_version($extension_name);
+ $local_cache = update_get_file($latest_version['download_link']);
+ $extension_destination_dir = ($extension_type == UPDATE_EXTENSION_TYPE_MODULE) ? DRUPAL_ROOT . '/sites/all/modules/' . $extension_name : DRUPAL_ROOT . '/sites/all/themes/' . $extension_name;
+ if (update_untar($local_cache)) {
+ $extension_source_dir = file_directory_temp() . '/update-extraction/' . $extension_name;
+ }
+ try {
+ $filetransfer->removeDirectory($extension_destination_dir);
+ $filetransfer->copyDirectory($extension_source_dir, $extension_destination_dir);
+ }
+ catch(Exception $e) {
+ drupal_set_message(t($e->getMessage(), $e->arguments), 'error');
+ // Some better error handling is needed, but batch API doesn't seem to support any.
+ throw $e;
+ }
+
+ $context['finished'] = 1;
+
+}
+
+function update_install_extension($extension_name, &$context) {
+ if (!isset($context['sandbox']['done'])) {
+ $context['sandbox']['done'] = 0;
+ }
+ if (!$context['results']) {
+ $context['results'][] = t('Installed %extension', array('%extension' => $extension_name));
+ }
+
+ $context['message'] = t('Installing %extension', array('%extension' => $extension_name));
+ sleep(1);
+ $context['sandbox']['done'] += 1;
+ $context['finished'] = $context['sandbox']['done'] / 4;
+}
+
+function update_batch_finished($success, $results) {
+ if ($success) {
+ variable_set('site_offline', FALSE);
+ }
+ $_SESSION['update_batch_results']['success'] = $success;
+ $_SESSION['update_batch_results']['messages'] = $results;
+}
+
+function update_get_default_filetransfer($overrides = array()) {
+ //Fire up the connection class
+ $update_filetransfer_default = variable_get('update_filetransfer_default', NULL);
+ $settings = variable_get("update_filetransfer_connection_settings_" . $update_filetransfer_default, array());
+ $settings = array_merge($settings, $overrides);
+ $available_backends = module_invoke_all('filetransfer_backends');
+ $filetransfer = call_user_func_array("{$available_backends[$update_filetransfer_default]['class']}::factory", array(DRUPAL_ROOT, $settings));
+ return $filetransfer;
+}