| 1 |
<?php
|
| 2 |
// $Id: plugin_manager.module,v 1.52 2008/08/19 21:49:01 joshuarogers Exp $
|
| 3 |
|
| 4 |
/**
|
| 5 |
* @file
|
| 6 |
* Several functions needed by the plugin manager.
|
| 7 |
*
|
| 8 |
* The plugin manager allows users to select and install new
|
| 9 |
* themes and modules directly from d.o.
|
| 10 |
*/
|
| 11 |
|
| 12 |
/**
|
| 13 |
* Implementation of hook_menu().
|
| 14 |
*/
|
| 15 |
function plugin_manager_menu() {
|
| 16 |
$items['admin/build/plugin_manager'] = array(
|
| 17 |
'title' => 'Plugin Manager',
|
| 18 |
'description' => 'Download and install new themes and modules in one step.',
|
| 19 |
'page callback' => 'drupal_get_form',
|
| 20 |
'page arguments' => array('plugin_manager_overview'),
|
| 21 |
'access arguments' => array('install plugins'),
|
| 22 |
'file' => 'plugin_manager.admin.inc',
|
| 23 |
);
|
| 24 |
$items['admin/build/plugin_manager/overview'] = array(
|
| 25 |
'title' => 'Overview',
|
| 26 |
'description' => 'Download and install new themes and modules in one step.',
|
| 27 |
'page callback' => 'drupal_get_form',
|
| 28 |
'page arguments' => array('plugin_manager_overview'),
|
| 29 |
'access arguments' => array('install plugins'),
|
| 30 |
'file' => 'plugin_manager.admin.inc',
|
| 31 |
'type' => MENU_DEFAULT_LOCAL_TASK,
|
| 32 |
'weight' => 1,
|
| 33 |
);
|
| 34 |
$items['admin/build/plugin_manager/modules'] = array(
|
| 35 |
'title' => 'Modules',
|
| 36 |
'page callback' => 'plugin_manager_modules',
|
| 37 |
'access arguments' => array('install plugins'),
|
| 38 |
'file' => 'plugin_manager.admin.inc',
|
| 39 |
'type' => MENU_LOCAL_TASK,
|
| 40 |
'weight' => 2,
|
| 41 |
);
|
| 42 |
$items['admin/build/plugin_manager/themes'] = array(
|
| 43 |
'title' => 'Themes',
|
| 44 |
'page callback' => 'drupal_get_form',
|
| 45 |
'page arguments' => array('plugin_manager_category_form'),
|
| 46 |
'access arguments' => array('install plugins'),
|
| 47 |
'file' => 'plugin_manager.admin.inc',
|
| 48 |
'type' => MENU_LOCAL_TASK,
|
| 49 |
'weight' => 3,
|
| 50 |
);
|
| 51 |
$items['admin/build/plugin_manager/install'] = array(
|
| 52 |
'title' => 'Install',
|
| 53 |
'page callback' => 'drupal_get_form',
|
| 54 |
'page arguments' => array('plugin_manager_install_form'),
|
| 55 |
'access arguments' => array('install plugins'),
|
| 56 |
'file' => 'plugin_manager.admin.inc',
|
| 57 |
'type' => MENU_LOCAL_TASK,
|
| 58 |
'weight' => 4,
|
| 59 |
);
|
| 60 |
$items['admin/build/plugin_manager/uninstall'] = array(
|
| 61 |
'title' => 'Uninstall',
|
| 62 |
'page callback' => 'drupal_get_form',
|
| 63 |
'page arguments' => array('plugin_manager_uninstall_form'),
|
| 64 |
'access arguments' => array('uninstall plugins'),
|
| 65 |
'file' => 'plugin_manager.admin.inc',
|
| 66 |
'type' => MENU_LOCAL_TASK,
|
| 67 |
'weight' => 5,
|
| 68 |
);
|
| 69 |
return $items;
|
| 70 |
}
|
| 71 |
|
| 72 |
/**
|
| 73 |
* Implementation of hook_help().
|
| 74 |
*/
|
| 75 |
function plugin_manager_help($path, $arg) {
|
| 76 |
switch ($path) {
|
| 77 |
case 'admin/build/plugin_manager/overview':
|
| 78 |
case 'admin/build/plugin_manager':
|
| 79 |
return '<p>'. t('This allows users to install new modules and themes much more easily. To use this module, click on the Modules tab to browse Drupal.org\'s list of modules, select which modules you want installed, then repeat the same with the Themes tab. Alternatively, use the search box below to look for modules and themes. Finally, click on the Install tab to continue with fetching and installing the modules.') .'</p>';
|
| 80 |
case 'admin/build/plugin_manager/install':
|
| 81 |
return '<p><strong>'. t('Note: the more items you select, the longer the installation will take, potentially causing it to time out.') .'</strong></p>';
|
| 82 |
case 'admin/build/plugin_manager/uninstall':
|
| 83 |
return '<p>'. t('This will only show plugins that are not currently in use and that were installed using the plugin manager.') .'</p>';
|
| 84 |
}
|
| 85 |
}
|
| 86 |
|
| 87 |
/**
|
| 88 |
* Implementation of hook_perm().
|
| 89 |
*/
|
| 90 |
function plugin_manager_perm() {
|
| 91 |
return array('install plugins', 'uninstall plugins');
|
| 92 |
}
|
| 93 |
|
| 94 |
/**
|
| 95 |
* Get a list of all available backends that can upload files onto our system.
|
| 96 |
*
|
| 97 |
* @return
|
| 98 |
* Array containing the names of all available frontends.
|
| 99 |
*/
|
| 100 |
function plugin_manager_backends() {
|
| 101 |
$backend = array();
|
| 102 |
// Open that directory to view the contained files / folders
|
| 103 |
if ($handle = opendir(dirname(__FILE__))) {
|
| 104 |
// Look through the modules of that folder
|
| 105 |
while ($current = readdir($handle)) {
|
| 106 |
// If the file is a backend file then load it.
|
| 107 |
if (strstr($current, ".backend.inc") == ".backend.inc") {
|
| 108 |
include_once($current);
|
| 109 |
// If there is a backend hook, then run it.
|
| 110 |
$name = str_replace('.backend.inc', '', $current);
|
| 111 |
if (function_exists($name .'_plugin_manager_backend')) {
|
| 112 |
$output = call_user_func($name .'_plugin_manager_backend');
|
| 113 |
// If the backend is available, note it.
|
| 114 |
if (!empty($output)) {
|
| 115 |
$backend[$output] = $output;
|
| 116 |
}
|
| 117 |
}
|
| 118 |
}
|
| 119 |
}
|
| 120 |
}
|
| 121 |
|
| 122 |
sort($backend);
|
| 123 |
return $backend;
|
| 124 |
}
|
| 125 |
|
| 126 |
/**
|
| 127 |
* Attempts to get a file using drupal_http_request and to store it locally.
|
| 128 |
*
|
| 129 |
* @param $path
|
| 130 |
* The URL of the file to grab.
|
| 131 |
* @return
|
| 132 |
* On success the address the files was saved to, FALSE on failure.
|
| 133 |
*/
|
| 134 |
function plugin_manager_get($path) {
|
| 135 |
// Get each of the specified files.
|
| 136 |
$parsed_url = parse_url($path);
|
| 137 |
$local = file_directory_path() ."/plugin_manager_cache/". basename($parsed_url['path']);
|
| 138 |
|
| 139 |
// Check the cache and download the file if needed
|
| 140 |
if (!file_exists($local)) {
|
| 141 |
|
| 142 |
// $result->data is the actual contents of the downloaded file. This saves it
|
| 143 |
// into a local file, whose path is stored in $local. $local is stored relative
|
| 144 |
// to the drupal installation.
|
| 145 |
$result = drupal_http_request($path);
|
| 146 |
if ($result->code != 200 OR !file_save_data($result->data, $local)) {
|
| 147 |
drupal_set_message(t('@remote could not be saved.', array('@remote' => $path)), 'error');
|
| 148 |
return FALSE;
|
| 149 |
}
|
| 150 |
}
|
| 151 |
return $local;
|
| 152 |
}
|
| 153 |
|
| 154 |
/**
|
| 155 |
* Untars a file.
|
| 156 |
*
|
| 157 |
* @param $file
|
| 158 |
* The file to untar.
|
| 159 |
* @return
|
| 160 |
* An array containing the locations of the extracted files.
|
| 161 |
*/
|
| 162 |
function plugin_manager_untar($file) {
|
| 163 |
$dir = file_directory_path() .'/plugin_manager_extraction/';
|
| 164 |
$file_safe = escapeshellarg($file);
|
| 165 |
$dir_safe = escapeshellarg($dir);
|
| 166 |
$file_list = array();
|
| 167 |
|
| 168 |
// Try to use tar to extract the files.
|
| 169 |
$handle = popen("tar -zvxf $file_safe -C $dir_safe", "r");
|
| 170 |
while ($line = fgets($handle)) {
|
| 171 |
$file_list[] = trim($line);
|
| 172 |
}
|
| 173 |
pclose($handle);
|
| 174 |
|
| 175 |
// If tar returned something (a.k.a, is present) then return it
|
| 176 |
if (!empty($file_list)) {
|
| 177 |
return $file_list;
|
| 178 |
}
|
| 179 |
|
| 180 |
// If we get this far then tar failed. Attempt to extract using PEAR's Archive/Tar.
|
| 181 |
// This should still be GPL safe since this modules does not depend on PEAR.
|
| 182 |
@include_once("Archive/Tar.php");
|
| 183 |
|
| 184 |
// If it doesn't exist either, then we can't explode the files.
|
| 185 |
if (!class_exists("Archive_Tar")) {
|
| 186 |
drupal_set_message(t('Neither the tar executable nor the Archive/Tar package could be located.'), "error");
|
| 187 |
return FALSE;
|
| 188 |
}
|
| 189 |
|
| 190 |
// Attempt to explode the file with PEAR.
|
| 191 |
$tar = new Archive_Tar($file);
|
| 192 |
$tar->extract($dir);
|
| 193 |
|
| 194 |
// Get a list of the extracted files.
|
| 195 |
foreach ($tar->listcontent() AS $file) {
|
| 196 |
$file_list[] = trim($file['filename']);
|
| 197 |
}
|
| 198 |
|
| 199 |
// Return the list
|
| 200 |
return $file_list;
|
| 201 |
}
|
| 202 |
|
| 203 |
/**
|
| 204 |
* Downloads the list of available themes/modules.
|
| 205 |
*
|
| 206 |
* @return
|
| 207 |
* TRUE if the repository is / can be made up-to-date, FALSE otherwise.
|
| 208 |
*/
|
| 209 |
function plugin_manager_reload() {
|
| 210 |
if (variable_get("plugin_manager_last_reload", 0) + 86400 >= date('U')) {
|
| 211 |
return TRUE;
|
| 212 |
}
|
| 213 |
|
| 214 |
// Download a new copy of the project-list.
|
| 215 |
$file = drupal_http_request("http://updates.drupal.org/release-history/project-list/all");
|
| 216 |
if (isset($file->error)) {
|
| 217 |
drupal_set_message(t($file->error), 'error');
|
| 218 |
return FALSE;
|
| 219 |
}
|
| 220 |
|
| 221 |
// Parse it.
|
| 222 |
$xml = simplexml_load_string($file->data);
|
| 223 |
if ($xml == FALSE) {
|
| 224 |
return FALSE;
|
| 225 |
}
|
| 226 |
|
| 227 |
// Clear the current cache.
|
| 228 |
db_query("DELETE FROM {plugin_manager_repository}");
|
| 229 |
db_query("DELETE FROM {plugin_manager_taxonomy}");
|
| 230 |
|
| 231 |
// Look at each project node.
|
| 232 |
$drupal_version = constant("DRUPAL_CORE_COMPATIBILITY");
|
| 233 |
foreach ($xml->project AS $project) {
|
| 234 |
// If there isn't a release for this version of Drupal then skip it.
|
| 235 |
if (!isset($project->api_versions)) {
|
| 236 |
continue;
|
| 237 |
}
|
| 238 |
$versions = (array) $project->api_versions;
|
| 239 |
if (!is_array($versions['api_version'])) {
|
| 240 |
$versions['api_version'] = array($versions['api_version']);
|
| 241 |
}
|
| 242 |
if (!in_array($drupal_version, $versions['api_version'])) {
|
| 243 |
continue;
|
| 244 |
}
|
| 245 |
|
| 246 |
// Toss it in the database
|
| 247 |
$short_name = $project->short_name;
|
| 248 |
db_query("INSERT INTO {plugin_manager_repository} (title, short_name, links)
|
| 249 |
VALUES('%s', '%s', '%s')", $project->title, $short_name, $project->link);
|
| 250 |
|
| 251 |
// Find the appropriate taxonomy terms.
|
| 252 |
if (isset($project->terms)) {
|
| 253 |
foreach ($project->terms->term AS $term) {
|
| 254 |
db_query("INSERT INTO {plugin_manager_taxonomy} (short_name, tag)
|
| 255 |
VALUES('%s', '%s')", $short_name, $term->value);
|
| 256 |
}
|
| 257 |
}
|
| 258 |
}
|
| 259 |
drupal_set_message(t("The repository was updated successfully."), "status");
|
| 260 |
variable_set("plugin_manager_last_reload", date('U'));
|
| 261 |
return TRUE;
|
| 262 |
}
|
| 263 |
|
| 264 |
/**
|
| 265 |
* Get the information about each plugin.
|
| 266 |
*
|
| 267 |
* @param $projects
|
| 268 |
* The project or projects on which information is desired.
|
| 269 |
* @return
|
| 270 |
* An array containing info on the supplied projects.
|
| 271 |
*/
|
| 272 |
function plugin_manager_get_release_history($projects) {
|
| 273 |
$version = constant("DRUPAL_CORE_COMPATIBILITY");
|
| 274 |
$results = array();
|
| 275 |
|
| 276 |
// If projects isn't an array, turn it into one.
|
| 277 |
if (!is_array($projects)) {
|
| 278 |
$projects = array($projects);
|
| 279 |
}
|
| 280 |
|
| 281 |
// Look up the data for every project requested.
|
| 282 |
foreach ($projects AS $project) {
|
| 283 |
$file = drupal_http_request("http://updates.drupal.org/release-history/$project/$version");
|
| 284 |
$xml = simplexml_load_string($file->data);
|
| 285 |
|
| 286 |
// If it failed, then quit.
|
| 287 |
if ($xml == FALSE) {
|
| 288 |
drupal_set_message(t("Downloading the release history failed for @project.", array('@project' => $project)), "error");
|
| 289 |
return FALSE;
|
| 290 |
}
|
| 291 |
|
| 292 |
// Get the title, release_link and download_link.
|
| 293 |
$results[$project]['title'] = (string)$xml->title;
|
| 294 |
|
| 295 |
// Get the information about every release
|
| 296 |
foreach ($xml->releases->release AS $release) {
|
| 297 |
$release_version = (string)$release->version;
|
| 298 |
$results[$project]['release'][] = array(
|
| 299 |
'release_link' => (string)$release->release_link,
|
| 300 |
'download_link' => (string)$release->download_link,
|
| 301 |
'date' => (string)$release->date,
|
| 302 |
'version' => $release_version,
|
| 303 |
);
|
| 304 |
$results[$project]['version'][] = $release_version;
|
| 305 |
}
|
| 306 |
}
|
| 307 |
|
| 308 |
// Order them and then return the results.
|
| 309 |
ksort($results);
|
| 310 |
return $results;
|
| 311 |
}
|
| 312 |
|
| 313 |
/**
|
| 314 |
* See if everything that is needed to use the plugin manager is available.
|
| 315 |
*
|
| 316 |
* @return
|
| 317 |
* TRUE if all of the required dependencies are available, FALSE otherwise.
|
| 318 |
*/
|
| 319 |
function plugin_manager_runnable() {
|
| 320 |
// See if we have a way to untar the files.
|
| 321 |
@include_once("Archive/Tar.php");
|
| 322 |
$handle = popen("tar --version", "r");
|
| 323 |
if (!fgets($handle) AND !class_exists("Archive_Tar")) {
|
| 324 |
drupal_set_message(t('The plugin manager cannot run because neither the tar executable nor the Archive/Tar package could be located.'), "error");
|
| 325 |
return FALSE;
|
| 326 |
}
|
| 327 |
pclose($handle);
|
| 328 |
|
| 329 |
// See if we have any available backends.
|
| 330 |
$backends = plugin_manager_backends();
|
| 331 |
if (empty($backends)) {
|
| 332 |
drupal_set_message(t('No backends are usable.'), 'error');
|
| 333 |
return FALSE;
|
| 334 |
}
|
| 335 |
|
| 336 |
return TRUE;
|
| 337 |
}
|