| 1 |
<?php
|
| 2 |
// $Id: package_builder.module,v 1.5 2008/02/09 20:26:26 shawnconn Exp $
|
| 3 |
|
| 4 |
/**
|
| 5 |
* @file
|
| 6 |
* Builds customized Drupal packages
|
| 7 |
*
|
| 8 |
* The package builder module consists mostly of a single form. Users can input
|
| 9 |
* the drupal package, and modules they wish to include in the package. After
|
| 10 |
* entering some further information needed to build a Drupal a profile,
|
| 11 |
* submitting the form will output a bundled tarball that includes drupal, the
|
| 12 |
* specified modules, and the installation profile.
|
| 13 |
*
|
| 14 |
* Module is dependent on PEAR's Archive_Tar and PHP's zlib functions for
|
| 15 |
* handling of tarballs
|
| 16 |
* http://pear.php.net/package/Archive_Tar
|
| 17 |
* http://us2.php.net/manual/en/ref.zlib.php
|
| 18 |
*
|
| 19 |
* Module is dependent on cURL for handle downloading tarballs from drupal.org
|
| 20 |
* http://www.php.net/curl
|
| 21 |
*
|
| 22 |
* Development sponsored by the Ubercart project. http://www.ubercart.org
|
| 23 |
* Written By Shawn Conn. http://www.shawnconn.com/
|
| 24 |
*/
|
| 25 |
|
| 26 |
include_once('PEAR.php');
|
| 27 |
include_once ('Archive/Tar.php');
|
| 28 |
define('PACKAGE_BUILDER_EXPIRATION_LENGTH', 86400);
|
| 29 |
|
| 30 |
/*******************************************************************************
|
| 31 |
* Hook Functions (Drupal)
|
| 32 |
*******************************************************************************/
|
| 33 |
|
| 34 |
/**
|
| 35 |
* Implementation of hook_cron().
|
| 36 |
*/
|
| 37 |
function package_builder_cron() {
|
| 38 |
$now = time();
|
| 39 |
$projects = db_query("SELECT `checked`, `project_name`,`info` FROM {package_builder_projects} WHERE `module_name` IS NULL");
|
| 40 |
while ($project = db_fetch_object($projects)) {
|
| 41 |
if ($now > $project->checked + PACKAGE_BUILDER_EXPIRATION_LENGTH) {
|
| 42 |
if ($updated_project_info = _package_builder_release_info($project->project_name)) {
|
| 43 |
db_query("UPDATE {package_builder_projects} SET `checked` = %d, `info` = '%s' WHERE `project_name` = '%s' AND `module_name` IS NULL",$now,serialize($updated_project_info),$project->project_name);
|
| 44 |
watchdog('package_builder',t('Project release information has been updated for %project_name',array('%project_name' => $updated_project_info['title'])));
|
| 45 |
}
|
| 46 |
else {
|
| 47 |
$project_info = unserialize($project->info);
|
| 48 |
watchdog('package_builder',t('Failed to retrieve release information for %project_name',array('%project_name' => $project_info['title'])),WATCHDOG_WARNING);
|
| 49 |
}
|
| 50 |
}
|
| 51 |
}
|
| 52 |
}
|
| 53 |
|
| 54 |
/**
|
| 55 |
* Implementation of hook_help().
|
| 56 |
*/
|
| 57 |
function package_builder_help($section){
|
| 58 |
switch ($section){
|
| 59 |
case 'admin/build/package':
|
| 60 |
return t('To build your custom Drupal package follow the instructions below.');
|
| 61 |
}
|
| 62 |
}
|
| 63 |
|
| 64 |
/**
|
| 65 |
* Implementation of hook_menu().
|
| 66 |
*/
|
| 67 |
function package_builder_menu($may_cache) {
|
| 68 |
if ($may_cache) {
|
| 69 |
$items[] = array(
|
| 70 |
'path' => 'admin/build/package',
|
| 71 |
'title' => t('Package builder'),
|
| 72 |
'access' => user_access('access package builder'),
|
| 73 |
'callback' => 'drupal_get_form',
|
| 74 |
'callback arguments' => array('package_builder_form'),
|
| 75 |
'description' => t('Build a customized Drupal package.'),
|
| 76 |
'type' => MENU_NORMAL_ITEM,
|
| 77 |
);
|
| 78 |
}
|
| 79 |
else {
|
| 80 |
$items[] = array(
|
| 81 |
'path' => 'admin/build/package/delete/'.arg(4),
|
| 82 |
'title' => t('Delete package'),
|
| 83 |
'access' => user_access('access package builder'),
|
| 84 |
'callback' => 'drupal_get_form',
|
| 85 |
'callback arguments' => array('package_builder_delete_form',arg(4)),
|
| 86 |
'description' => t('Delete a specified package.'),
|
| 87 |
'type' => MENU_CALLBACK,
|
| 88 |
);
|
| 89 |
drupal_add_css(drupal_get_path('module', 'package_builder') .'/package_builder.css');
|
| 90 |
}
|
| 91 |
return $items;
|
| 92 |
}
|
| 93 |
|
| 94 |
/**
|
| 95 |
* Implementation of hook_perm().
|
| 96 |
*/
|
| 97 |
function package_builder_perm() {
|
| 98 |
return array('access package builder');
|
| 99 |
}
|
| 100 |
|
| 101 |
/*******************************************************************************
|
| 102 |
* Callback Functions, Forms, and Tables
|
| 103 |
*******************************************************************************/
|
| 104 |
|
| 105 |
function theme_package_builder_projects($project) {
|
| 106 |
$output = '<p>'.t('To add projects to the package enter the drupal.org short name (see description below) of the project and click "Add project". Projects will be hightlighted as either <span class="package_builder_module_row">module</span> or <span class="package_builder_theme_row">theme</span> projects. The select box next to the project name will let you choose which project version release to use in the package. Clicking the checkbox next to a module name will enable the module (and its dependent modules) upon installation of the package. Projects can be removed by clicking the checkbox on the right side of the project header.').'</p>';
|
| 107 |
$output .= drupal_render($project['package_project_name']);
|
| 108 |
$output .= drupal_render($project['add_project']);
|
| 109 |
$output .= '<table class="package_builder_project_table"><thead><th colspan="2">'.t('Name').'</th><th>'.t('Version').'</th><th class="package_builder_project_remove" colspan="2">'.t('Remove').'</th></thead><tbody>';
|
| 110 |
foreach ($project as $key => $value) {
|
| 111 |
if ($key[0] != '#' && !is_null($value['version'])) {
|
| 112 |
$project_info = unserialize($project[$key]['info']['#value']);
|
| 113 |
$type = $project[$key]['type']['#value'];
|
| 114 |
$output .= '<tr class="package_builder_'.$type.'_row"><td class="package_builder_project_name" colspan="2">'.l($project_info['title'],"http://drupal.org/project/$key").'</td><td>'.drupal_render($project[$key.'_versions']).'</td><td></td><td class="package_builder_project_remove">'.drupal_render($project[$key.'_remove']).'</td></tr>';
|
| 115 |
if ($type == 'module') {
|
| 116 |
$output .= '<tr class="package_builder_'.$type.'_header"><td colspan="2"></td><td colspan="3"">'.t('Description').'</td></tr>';
|
| 117 |
foreach (array_keys($project['modules_info'][$key]) as $module) {
|
| 118 |
if ($module[0] != '#') {
|
| 119 |
$module_info = unserialize($project['modules_info'][$key][$module]['#value']);
|
| 120 |
$output .= '<tr class="package_builder_'.$type.'_subrow"><td>'.drupal_render($project['modules'][$key][$module.'_install']).'</td><td class="package_builder_module_name">'.$module_info['name'].'</td><td colspan="3" class="description">'.$module_info['description'].'<br/>'.$project['modules'][$key][$module.'_dependencies']['#default_value'].'</td></tr>';
|
| 121 |
}
|
| 122 |
}
|
| 123 |
}
|
| 124 |
}
|
| 125 |
}
|
| 126 |
$output .= '</tbody></table>';
|
| 127 |
$output .= drupal_render($project);
|
| 128 |
return $output;
|
| 129 |
}
|
| 130 |
|
| 131 |
function package_builder_delete_form($package) {
|
| 132 |
$package = urldecode($package);
|
| 133 |
$package_dir = variable_get('file_directory_path','files').'/package_builder';
|
| 134 |
if (is_file("$package_dir/$package")) {
|
| 135 |
$form['package'] = array(
|
| 136 |
'#type' => 'value',
|
| 137 |
'#value' => "$package_dir/$package",
|
| 138 |
);
|
| 139 |
$form = confirm_form($form,t('Delete the package %package_name?',array('%package_name' => $package)),'admin/build/package',t('This action can not be undone.'),t('Yes'),t('No'));
|
| 140 |
}
|
| 141 |
else {
|
| 142 |
drupal_set_message(t('Invalid file'),'error');
|
| 143 |
}
|
| 144 |
return $form;
|
| 145 |
}
|
| 146 |
function package_builder_delete_form_submit($form_id, $form_values) {
|
| 147 |
if (unlink($form_values['package'])) {
|
| 148 |
drupal_set_message(t('%package_name has been deleted',array('%package_name' => basename($form_values['package']))));
|
| 149 |
}
|
| 150 |
drupal_goto('admin/build/package');
|
| 151 |
}
|
| 152 |
|
| 153 |
function package_builder_form() {
|
| 154 |
if (!db_result(db_query("SELECT `version` FROM {package_builder_projects} WHERE `project_name` = 'drupal' AND `module_name` IS NULL"))) {
|
| 155 |
_package_builder_add_project('drupal');
|
| 156 |
}
|
| 157 |
$package_dir = variable_get('file_directory_path','files').'/package_builder';
|
| 158 |
foreach (file_scan_directory($package_dir,".+\.(t|T)(a|A)(r|R)\.(g|G)(z|Z)",array('.', '..', 'CVS'),0,FALSE) as $path => $package) {
|
| 159 |
$packages .= '<li><a href="'.url($path).'">'.basename($path).'</a> ('.t('<a href="!url">delete</a>',array('!url' => url('admin/build/package/delete/'.basename($path)))).')</li>';
|
| 160 |
}
|
| 161 |
$form['existing_packages'] = array(
|
| 162 |
'#type' => 'markup',
|
| 163 |
'#value' => '<div class="package_builder_existing_projects"><strong>'.t('Existing packages:').'</strong><br/><ul>'.$packages.'</ul></div><div class="description">'.t('Previously created packages by the package builder').'</div>',
|
| 164 |
);
|
| 165 |
$form['package_short_name'] = array(
|
| 166 |
'#type' => 'textfield',
|
| 167 |
'#title' => t('Package name'),
|
| 168 |
'#default_value' => variable_get('package_builder_default_short_name','profile'),
|
| 169 |
'#description' => t('The name of the package (may only contain lower case letters and the "_" character)'),
|
| 170 |
'#maxlength' => 50,
|
| 171 |
);
|
| 172 |
$form['project'] = array(
|
| 173 |
'#type' => 'fieldset',
|
| 174 |
'#title' => t('Included projects'),
|
| 175 |
'#collapsible' => TRUE,
|
| 176 |
'#collapsed' => FALSE,
|
| 177 |
);
|
| 178 |
$form['project']['package_project_name'] = array(
|
| 179 |
'#type' => 'textfield',
|
| 180 |
'#title' => t('Project short name'),
|
| 181 |
'#description' => t('The short name of the project to add to the package. This can be found by looking at the project page on <a href="!drupal_url">drupal.org</a>. (e.g. the Drupal project page is http://drupal.org/project/<strong>drupal</strong> thus <strong>drupal</strong> would be the project short name)',array('!drupal_url' => 'http://drupal.org/')),
|
| 182 |
'#maxlength' => 255,
|
| 183 |
);
|
| 184 |
$form['project']['add_project'] = array(
|
| 185 |
'#type' => 'submit',
|
| 186 |
'#value' => t('Add project'),
|
| 187 |
);
|
| 188 |
|
| 189 |
//Load current package projects
|
| 190 |
$projects = db_query("SELECT `project_name`, `version`, `info` FROM {package_builder_projects} WHERE `module_name` IS NULL ORDER BY `project_name` ASC");
|
| 191 |
while ($project = db_fetch_object($projects)) {
|
| 192 |
$info = unserialize($project->info);
|
| 193 |
foreach ($info['releases'] as $version => $release) {
|
| 194 |
$releases[$version] = $version;
|
| 195 |
}
|
| 196 |
$form['project'][$project->project_name]['version'] = array(
|
| 197 |
'#type' => 'value',
|
| 198 |
'#value' => $project->version,
|
| 199 |
);
|
| 200 |
$form['project'][$project->project_name]['info'] = array(
|
| 201 |
'#type' => 'value',
|
| 202 |
'#value' => $project->info,
|
| 203 |
);
|
| 204 |
$form['project'][$project->project_name.'_versions'] = array(
|
| 205 |
'#type' => 'select',
|
| 206 |
'#default_value' => $project->version,
|
| 207 |
'#options' => $releases,
|
| 208 |
'#attributes' => array('onchange' => "document.package_builder_form.submit();"),
|
| 209 |
);
|
| 210 |
if ($project->project_name != 'drupal') {
|
| 211 |
$form['project'][$project->project_name.'_remove'] = array (
|
| 212 |
'#type' => 'checkbox',
|
| 213 |
'#attributes' => array('onchange' => "document.package_builder_form.submit();"),
|
| 214 |
);
|
| 215 |
}
|
| 216 |
|
| 217 |
//Load project modules
|
| 218 |
$modules = db_query("SELECT `module_name`,`info`,`install` FROM {package_builder_projects} WHERE `cache` IS NULL AND `project_name` = '%s'",$project->project_name);
|
| 219 |
$form['project'][$project->project_name]['type'] = array(
|
| 220 |
'#type' => 'value',
|
| 221 |
'#value' => (db_num_rows($modules) == 0) ? 'theme' : 'module',
|
| 222 |
);
|
| 223 |
while ($module = db_fetch_object($modules)) {
|
| 224 |
$module_info = unserialize($module->info);
|
| 225 |
$form['project']['modules'][$project->project_name][$module->module_name.'_install'] = array (
|
| 226 |
'#type' => 'checkbox',
|
| 227 |
'#default_value' => $module->install,
|
| 228 |
);
|
| 229 |
if ($project->project_name == 'drupal' && in_array($module->module_name,_package_builder_required_drupal())) {
|
| 230 |
$form['project']['modules'][$project->project_name][$module->module_name.'_install']['#attributes']['disabled'] = TRUE;
|
| 231 |
}
|
| 232 |
//Check for module dependencies
|
| 233 |
if (!empty($module_info['dependencies'])) {
|
| 234 |
foreach ($module_info['dependencies'] as $dependency) {
|
| 235 |
if ($dependency_info = db_result(db_query("SELECT `info` FROM {package_builder_projects} WHERE `module_name` = '%s'",$dependency))) {
|
| 236 |
$dependency_info = unserialize($dependency_info);
|
| 237 |
$module_dependencies .= $dependency_info['name'].', ';
|
| 238 |
}
|
| 239 |
else {
|
| 240 |
$module_dependencies .= $dependency.t(' (<span class="admin-missing">missing</span>), ');
|
| 241 |
$form['project']['modules'][$project->project_name][$module->module_name.'_install']['#attributes']['disabled'] = TRUE;
|
| 242 |
}
|
| 243 |
}
|
| 244 |
$dependencies = t('<div class="admin-dependencies"><strong>Depends on:</strong> !dependencies</div>',array('!dependencies' => substr($module_dependencies, 0, -2)));
|
| 245 |
unset($module_dependencies);
|
| 246 |
}
|
| 247 |
$form['project']['modules'][$project->project_name][$module->module_name.'_dependencies'] = array (
|
| 248 |
'#type' => 'markup',
|
| 249 |
'#default_value' => $dependencies,
|
| 250 |
);
|
| 251 |
$form['project']['modules_info'][$project->project_name][$module->module_name] = array(
|
| 252 |
'#type' => 'value',
|
| 253 |
'#value' => $module->info,
|
| 254 |
);
|
| 255 |
unset($dependencies);
|
| 256 |
}
|
| 257 |
unset($releases);
|
| 258 |
}
|
| 259 |
$form['project']['#theme'] = 'package_builder_projects';
|
| 260 |
|
| 261 |
//Create profile for package
|
| 262 |
$form['profile'] = array(
|
| 263 |
'#type' => 'fieldset',
|
| 264 |
'#title' => t('Profile'),
|
| 265 |
'#collapsible' => TRUE,
|
| 266 |
'#collapsed' => FALSE,
|
| 267 |
);
|
| 268 |
$form['profile']['help'] = array(
|
| 269 |
'#type' => 'markup',
|
| 270 |
'#value' => '<p>'.t('Drupal <a href="!profile_url">installation profiles</a> allow you to customize your Drupal package further. To finish your package, add a name and description for the profile that will be bundled along with the package. Optionally, you can also add custom PHP code that will be executed after your Drupal package is installed.',array('!profile_url' => 'http://drupal.org/project/Installation+profiles')).'</p>',
|
| 271 |
);
|
| 272 |
$form['profile']['package_name'] = array(
|
| 273 |
'#type' => 'textfield',
|
| 274 |
'#title' => t('Profile name'),
|
| 275 |
'#default_value' => variable_get('package_builder_default_name','Profile'),
|
| 276 |
'#description' => t('The name of the Drupal profile to create.'),
|
| 277 |
'#maxlength' => 100,
|
| 278 |
);
|
| 279 |
$form['profile']['package_description'] = array(
|
| 280 |
'#type' => 'textarea',
|
| 281 |
'#title' => t('Profile description'),
|
| 282 |
'#description' => t("The description of the Drupal package to create."),
|
| 283 |
'#default_value' => variable_get('package_builder_default_description','A profile created by the Drupal Package Builder module.'),
|
| 284 |
'#cols' => 80,
|
| 285 |
'#rows' => 3,
|
| 286 |
);
|
| 287 |
$form['profile']['package_php'] = array(
|
| 288 |
'#type' => 'textarea',
|
| 289 |
'#title' => t('Profile PHP'),
|
| 290 |
'#description' => t("Any PHP code to run after installation of the package and its modules are complete, <?php ?> tags are not needed.<br/><strong>NOTE:</strong> This PHP code isn't evaluated for any syntax or logic errors. It is recommended you test the package installer after building it."),
|
| 291 |
'#default_value' => variable_get('package_builder_last_form_profile_final',""),
|
| 292 |
'#cols' => 80,
|
| 293 |
'#rows' => 20,
|
| 294 |
);
|
| 295 |
|
| 296 |
$form['save_settings'] = array(
|
| 297 |
'#type' => 'submit',
|
| 298 |
'#value' => t('Save settings'),
|
| 299 |
);
|
| 300 |
$form['build_package'] = array(
|
| 301 |
'#type' => 'submit',
|
| 302 |
'#value' => t('Build package'),
|
| 303 |
);
|
| 304 |
$form['#attributes'] = array(
|
| 305 |
'name' => 'package_builder_form'
|
| 306 |
);
|
| 307 |
return $form;
|
| 308 |
}
|
| 309 |
function package_builder_form_validate($form_id, $form_values) {
|
| 310 |
switch ($form_values['op']) {
|
| 311 |
case t('Add project'):
|
| 312 |
if (empty($form_values['package_project_name'])) {
|
| 313 |
form_set_error('package_project_name',t('Project short name is required.'));
|
| 314 |
}
|
| 315 |
elseif (!_package_builder_release_info($form_values['package_project_name'])) {
|
| 316 |
form_set_error('package_project_name',t('Could not retrieve project info for %short_name',array('%short_name' => $form_values['package_project_name'])));
|
| 317 |
}
|
| 318 |
elseif (db_result(db_query("SELECT `version` FROM {package_builder_projects} WHERE `project_name` = '%s' AND `install` IS NULL",$form_values['package_project_name']))) {
|
| 319 |
form_set_error('package_project_name',t('Could not add %short_name, it already has been added to the package',array('%short_name' => $form_values['package_project_name'])));
|
| 320 |
}
|
| 321 |
break;
|
| 322 |
case t('Save settings'):
|
| 323 |
case t('Build package'):
|
| 324 |
if (empty($form_values['package_name'])) {
|
| 325 |
form_set_error('package_name',t('Profile name is required'));
|
| 326 |
}
|
| 327 |
if (empty($form_values['package_description'])) {
|
| 328 |
form_set_error('package_description',t('Profile description is required'));
|
| 329 |
}
|
| 330 |
if (empty($form_values['package_short_name'])) {
|
| 331 |
form_set_error('package_short_name',t('Package short name is required'));
|
| 332 |
}
|
| 333 |
elseif (preg_match('/[^a-z_]/',$form_values['package_short_name'])) {
|
| 334 |
form_set_error('package_short_name',t('Package short name can only contain lower case letters or the "_" character'));
|
| 335 |
}
|
| 336 |
break;
|
| 337 |
default:
|
| 338 |
break;
|
| 339 |
}
|
| 340 |
}
|
| 341 |
function package_builder_form_submit($form_id, $form_values) {
|
| 342 |
switch ($form_values['op']) {
|
| 343 |
case t('Add project'):
|
| 344 |
_package_builder_add_project($form_values['package_project_name']);
|
| 345 |
break;
|
| 346 |
case t('Save settings'):
|
| 347 |
case t('Build package'):
|
| 348 |
foreach ($form_values as $key => $value) {
|
| 349 |
if (substr($key,-8) == '_install' && !in_array(str_replace('_install','',$key),_package_builder_required_drupal())) {
|
| 350 |
db_query("UPDATE {package_builder_projects} SET `install` = %d WHERE `module_name` = '%s'",$value,str_replace('_install','',$key));
|
| 351 |
}
|
| 352 |
}
|
| 353 |
variable_set('package_builder_default_short_name',$form_values['package_short_name']);
|
| 354 |
variable_set('package_builder_default_name',$form_values['package_name']);
|
| 355 |
variable_set('package_builder_default_description',$form_values['package_description']);
|
| 356 |
variable_set('package_builder_last_form_profile_final',$form_values['package_php']);
|
| 357 |
if ($form_values['op'] == t('Build package')) {
|
| 358 |
_package_builder_build_package();
|
| 359 |
}
|
| 360 |
else {
|
| 361 |
drupal_set_message(t('The package settings have been saved'));
|
| 362 |
}
|
| 363 |
break;
|
| 364 |
default: //Check for deleted or updated projects
|
| 365 |
foreach ($form_values as $key => $value) {
|
| 366 |
if (substr($key,-7) == '_remove' && $value) {
|
| 367 |
_package_builder_remove_project(str_replace('_remove','',$key));
|
| 368 |
}
|
| 369 |
if (substr($key,-9) == '_versions') {
|
| 370 |
$project = db_fetch_object(db_query("SELECT * FROM {package_builder_projects} WHERE `project_name` = '%s' AND `install` IS NULL",str_replace('_versions','',$key)));
|
| 371 |
$project_info = unserialize($project->info);
|
| 372 |
if ($project->version != $value && !empty($value)) {
|
| 373 |
_package_builder_remove_project($project->project_name, FALSE);
|
| 374 |
if (_package_builder_add_project($project->project_name, $value, FALSE)) {
|
| 375 |
$project = db_fetch_object(db_query("SELECT * FROM {package_builder_projects} WHERE `project_name` = '%s' AND `install` IS NULL",$project->project_name));
|
| 376 |
$project_info = unserialize($project->info);
|
| 377 |
drupal_set_message(t("Project %project_name has been switched to version %project_version",array('%project_name' => $project_info['title'],'%project_version' => $project->version)));
|
| 378 |
drupal_set_message(t("Project file cached at %file_path",array('%file_path' => $project->cache)));
|
| 379 |
}
|
| 380 |
else {
|
| 381 |
drupal_set_message(t("Project %project_name could not be switched to version %project_version. You will need to add the project again.",array('%project_name' => $project_info['title'],'%project_version' => $value)),'error');
|
| 382 |
}
|
| 383 |
}
|
| 384 |
}
|
| 385 |
}
|
| 386 |
break;
|
| 387 |
}
|
| 388 |
}
|
| 389 |
|
| 390 |
/*******************************************************************************
|
| 391 |
* Module and Helper Functions
|
| 392 |
*******************************************************************************/
|
| 393 |
|
| 394 |
/**
|
| 395 |
* Function adds modules found in a module project into the package_builder table
|
| 396 |
* @param $project
|
| 397 |
* The drupal.org short name of the project
|
| 398 |
*/
|
| 399 |
function _package_builder_add_modules($project) {
|
| 400 |
$file_path = db_result(db_query("SELECT cache FROM {package_builder_projects} WHERE project_name = '%s'",$project));
|
| 401 |
$temp_file = variable_get('file_directory_path','files').'/package_builder/tmp';
|
| 402 |
$project_tarball = new Archive_Tar($file_path);
|
| 403 |
$contents = $project_tarball->listContent();
|
| 404 |
|
| 405 |
foreach ($contents as $content) {
|
| 406 |
if (substr($content['filename'],-5) == ".info") {
|
| 407 |
$module = basename($content['filename'],'.info');
|
| 408 |
$enable = ($project == 'drupal' && in_array($module,_package_builder_required_drupal())) ? TRUE : FALSE;
|
| 409 |
$file = $project_tarball->extractInString($content['filename']);
|
| 410 |
file_put_contents($temp_file,$file);
|
| 411 |
$info = _module_parse_info_file($temp_file);
|
| 412 |
unlink($temp_file);
|
| 413 |
db_query("INSERT INTO {package_builder_projects} (`project_name`, `version`, `module_name`, `install`, `info`) VALUES ('%s', '%s', '%s', %d, '%s')",$project,$info['version'],$module,$enable,serialize($info));
|
| 414 |
}
|
| 415 |
}
|
| 416 |
}
|
| 417 |
|
| 418 |
/**
|
| 419 |
* Function adds a project into the package_builder table
|
| 420 |
* @param $project
|
| 421 |
* The drupal.org short name of the project
|
| 422 |
* @param $release
|
| 423 |
* The release version to cache and use for the project
|
| 424 |
* @param $notify
|
| 425 |
* If set to TRUE notifies user of the project addition & cached file
|
| 426 |
* @return:
|
| 427 |
* TRUE if successfully added, FALSE otherwise
|
| 428 |
*/
|
| 429 |
function _package_builder_add_project($project, $release = NULL, $notify = TRUE) {
|
| 430 |
$now = time();
|
| 431 |
$package_info = _package_builder_release_info($project);
|
| 432 |
if (is_null($release)) {
|
| 433 |
foreach ($package_info['releases'] as $version => $release) {
|
| 434 |
$download_url = $package_info['releases'][$version]['download_link'];
|
| 435 |
if (!empty($download_url)) {
|
| 436 |
$project_version = $version;
|
| 437 |
break;
|
| 438 |
}
|
| 439 |
}
|
| 440 |
}
|
| 441 |
else {
|
| 442 |
$download_url = $package_info['releases'][$release]['download_link'];
|
| 443 |
$project_version = $release;
|
| 444 |
}
|
| 445 |
|
| 446 |
if ($cache_file = _package_builder_retreive_project($download_url)) {
|
| 447 |
db_query("INSERT INTO {package_builder_projects} (`project_name`, `version`, `checked`, `cache`, `info`) VALUES ('%s', '%s', %d, '%s', '%s')",$project,$project_version,$now,$cache_file,serialize($package_info));
|
| 448 |
if ($notify) {
|
| 449 |
drupal_set_message(t("Project %project_name %project_version has been added to included projects",array('%project_name' => $package_info['title'],'%project_version' => $project_version)));
|
| 450 |
drupal_set_message(t("Project file cached at %file_path",array('%file_path' => $cache_file)));
|
| 451 |
}
|
| 452 |
_package_builder_add_modules($project);
|
| 453 |
return TRUE;
|
| 454 |
}
|
| 455 |
else {
|
| 456 |
form_set_error('package_project_name',t('An error occured in retrieving the project %project_name %project_version from the URL %project_url',array('%project_name' => $project,'%project_url' => $download_url,'%project_version' => $project_version)));
|
| 457 |
return FALSE;
|
| 458 |
}
|
| 459 |
}
|
| 460 |
|
| 461 |
/**
|
| 462 |
* Build a ordered list of modules to enabled based on their dependencies.
|
| 463 |
* @param $list
|
| 464 |
* An existing list of modules to enable
|
| 465 |
* @param $modules
|
| 466 |
* A database query object, containing the columns info & module_name, on the
|
| 467 |
* package_builder table whose rows are the modules to be enabled.
|
| 468 |
* @return:
|
| 469 |
* An ordered array of modules to enable
|
| 470 |
*/
|
| 471 |
function _package_builder_build_module_list($list, $modules) {
|
| 472 |
while ($module = db_fetch_object($modules)) {
|
| 473 |
if (!in_array($module->module_name,$list)) {
|
| 474 |
$module_info = unserialize($module->info);
|
| 475 |
if (!empty($module_info['dependencies'])) {
|
| 476 |
foreach ($module_info['dependencies'] as $dependency) {
|
| 477 |
if (!in_array($dependency,$list)) {
|
| 478 |
$other_dependencies = _package_builder_get_dependencies($dependency);
|
| 479 |
if (!empty($other_dependencies)) {
|
| 480 |
foreach ($other_dependencies as $new_dependency) {
|
| 481 |
if (!in_array($new_dependency,$list)) {
|
| 482 |
$list[] = $new_dependency;
|
| 483 |
}
|
| 484 |
}
|
| 485 |
}
|
| 486 |
$list[] = $dependency;
|
| 487 |
}
|
| 488 |
}
|
| 489 |
}
|
| 490 |
$list[] = $module->module_name;
|
| 491 |
}
|
| 492 |
}
|
| 493 |
return $list;
|
| 494 |
}
|
| 495 |
|
| 496 |
/**
|
| 497 |
* Build a drupal installation profile
|
| 498 |
* @param $notify
|
| 499 |
* If set to TRUE, notifies user of the package creation
|
| 500 |
*/
|
| 501 |
function _package_builder_build_package($notify = TRUE) {
|
| 502 |
include_once ('Archive/Tar.php');
|
| 503 |
|
| 504 |
$profile_name = variable_get('package_builder_default_short_name','profile');
|
| 505 |
$temp_dir = file_directory_temp().'/package_builder_'.md5($_SERVER['REMOTE_ADDR'].time());
|
| 506 |
$package_tarball = variable_get('file_directory_path','files')."/package_builder/$profile_name.tar.gz";
|
| 507 |
$temp_tarball = tempnam(file_directory_temp(),'package_builder');
|
| 508 |
$package = new Archive_Tar($temp_tarball,TRUE);
|
| 509 |
mkdir($temp_dir);
|
| 510 |
|
| 511 |
$drupal_tarball = db_result(db_query("SELECT `cache` FROM {package_builder_projects} WHERE `install` IS NULL AND `project_name` = 'drupal'"));
|
| 512 |
$drupal_package = new Archive_Tar($drupal_tarball);
|
| 513 |
$drupal_package->extractModify($temp_dir, basename($drupal_tarball, ".tar.gz"));
|
| 514 |
mkdir("$temp_dir/sites/all/modules");
|
| 515 |
mkdir("$temp_dir/sites/all/themes");
|
| 516 |
mkdir("$temp_dir/profiles/$profile_name");
|
| 517 |
|
| 518 |
$projects = db_query("SELECT `project_name`, `cache` FROM {package_builder_projects} WHERE `module_name` IS NULL AND `project_name` <> 'drupal'");
|
| 519 |
while ($project = db_fetch_object($projects)) {
|
| 520 |
$modules = db_result(db_query("SELECT COUNT(*) FROM {package_builder_projects} WHERE `project_name` = '%s' AND `cache` IS NULL",$project->project_name));
|
| 521 |
$dump_dir = ($modules == 0) ? "$temp_dir/sites/all/themes" : "$temp_dir/sites/all/modules";
|
| 522 |
$project_tarball = new Archive_Tar($project->cache);
|
| 523 |
$project_tarball->extractModify($dump_dir,'');
|
| 524 |
}
|
| 525 |
file_put_contents("$temp_dir/profiles/$profile_name/$profile_name.profile",_package_builder_build_profile($profile_name));
|
| 526 |
|
| 527 |
$package_files = _package_builder_read_dir($temp_dir);
|
| 528 |
$package->addModify($package_files,"$profile_name/",$temp_dir);
|
| 529 |
file_copy($temp_tarball,$package_tarball,FILE_EXISTS_REPLACE);
|
| 530 |
if ($notify) {
|
| 531 |
drupal_set_message(t('The package has been placed at <a href="!package_url">!package_name</a>',array('!package_url' => base_path().$package_tarball, '!package_name' => basename($package_tarball))));
|
| 532 |
}
|
| 533 |
}
|
| 534 |
|
| 535 |
/**
|
| 536 |
* Build a drupal installation profile
|
| 537 |
* @param $profile
|
| 538 |
* The name of the .profile installation profile to be generated
|
| 539 |
* @return:
|
| 540 |
* The contents of the .profile installation profile to be dumped into a file.
|
| 541 |
*/
|
| 542 |
function _package_builder_build_profile($profile) {
|
| 543 |
$profile_name = str_replace("'","\\'",variable_get('package_builder_default_name','Profile'));
|
| 544 |
$profile_description = str_replace("'","\\'",variable_get('package_builder_default_description','A profile created by the Drupal Package Builder module.'));
|
| 545 |
$profile_php = variable_get('package_builder_last_form_profile_final',"");
|
| 546 |
$module_list = _package_builder_required_drupal();
|
| 547 |
|
| 548 |
$drupal_modules = db_query("SELECT `module_name`,`info` FROM {package_builder_projects} WHERE `cache` IS NULL AND `project_name` = 'drupal' AND `install` = 1");
|
| 549 |
$module_list = _package_builder_build_module_list($module_list,$drupal_modules);
|
| 550 |
$other_modules = db_query("SELECT `module_name`,`info` FROM {package_builder_projects} WHERE `cache` IS NULL AND `project_name` <> 'drupal' AND `install` = 1");
|
| 551 |
$module_list = _package_builder_build_module_list($module_list,$other_modules);
|
| 552 |
|
| 553 |
foreach ($module_list as $index => $module) {
|
| 554 |
$module_list[$index] = "'$module'";
|
| 555 |
}
|
| 556 |
$installed_modules = implode(',',$module_list);
|
| 557 |
|
| 558 |
return "<?php
|
| 559 |
// Custom profile generated by package_builder module
|
| 560 |
|
| 561 |
/**
|
| 562 |
* Return an array of the modules to be enabled when this profile is installed.
|
| 563 |
*
|
| 564 |
* @return
|
| 565 |
* An array of modules to be enabled.
|
| 566 |
*/
|
| 567 |
function ".$profile."_profile_modules() {
|
| 568 |
return array($installed_modules);
|
| 569 |
}
|
| 570 |
|
| 571 |
/**
|
| 572 |
* Return a description of the profile for the initial installation screen.
|
| 573 |
*
|
| 574 |
* @return
|
| 575 |
* An array with keys 'name' and 'description' describing this profile.
|
| 576 |
*/
|
| 577 |
function ".$profile."_profile_details() {
|
| 578 |
return array(
|
| 579 |
'name' => '$profile_name',
|
| 580 |
'description' => '$profile_description'
|
| 581 |
);
|
| 582 |
}
|
| 583 |
|
| 584 |
/**
|
| 585 |
* Perform any final installation tasks for this profile.
|
| 586 |
*
|
| 587 |
* @return
|
| 588 |
* An optional HTML string to display to the user on the final installation
|
| 589 |
* screen.
|
| 590 |
*/
|
| 591 |
function ".$profile."_profile_final() {
|
| 592 |
$profile_php
|
| 593 |
}";
|
| 594 |
}
|
| 595 |
|
| 596 |
/**
|
| 597 |
* Get a list of dependencies (and their recursive dependencies) for a given
|
| 598 |
* module
|
| 599 |
* @param $module
|
| 600 |
* The name of the module to get the dependencies of.
|
| 601 |
* @return:
|
| 602 |
* An array containing the module's dependencies
|
| 603 |
*/
|
| 604 |
function _package_builder_get_dependencies($module) {
|
| 605 |
$output = array();
|
| 606 |
if ($module_info = db_result(db_query("SELECT `info` FROM {package_builder_projects} WHERE `module_name` = '%s'",$module))) {
|
| 607 |
$module_info = unserialize($module_info);
|
| 608 |
if (!empty($module_info['dependencies'])) {
|
| 609 |
foreach ($module_info['dependencies'] as $dependency) {
|
| 610 |
$other_dependencies = _package_builder_get_dependencies($dependency);
|
| 611 |
if (!empty($other_dependencies)) {
|
| 612 |
$output = $output + $other_dependencies;
|
| 613 |
}
|
| 614 |
$output[] = $dependency;
|
| 615 |
}
|
| 616 |
}
|
| 617 |
}
|
| 618 |
return $output;
|
| 619 |
}
|
| 620 |
|
| 621 |
/**
|
| 622 |
* A simplified version of Drupal's file_scan_directory that reads a dir and
|
| 623 |
* returns the all the files and directories contained within (including files
|
| 624 |
* that "." charcaters
|
| 625 |
* @param $dir
|
| 626 |
* The directory path to read
|
| 627 |
* @return:
|
| 628 |
* An array of files contained within the directory
|
| 629 |
*/
|
| 630 |
function _package_builder_read_dir($dir) {
|
| 631 |
$files = array();
|
| 632 |
if (is_dir($dir) && $handle = opendir($dir)) {
|
| 633 |
while ($file = readdir($handle)) {
|
| 634 |
if ($file != '.' && $file != '..') {
|
| 635 |
if (is_dir("$dir/$file")) {
|
| 636 |
$files = array_merge($files,_package_builder_read_dir("$dir/$file"));
|
| 637 |
}
|
| 638 |
else {
|
| 639 |
$files[] = "$dir/$file";
|
| 640 |
}
|
| 641 |
}
|
| 642 |
}
|
| 643 |
closedir($handle);
|
| 644 |
}
|
| 645 |
return $files;
|
| 646 |
}
|
| 647 |
|
| 648 |
/**
|
| 649 |
* Function returns list of required modules for Drupal core
|
| 650 |
* @return:
|
| 651 |
* An array of module names that make up Drupal core
|
| 652 |
*/
|
| 653 |
function _package_builder_required_drupal() {
|
| 654 |
return array('block', 'filter', 'node', 'system', 'user', 'watchdog');
|
| 655 |
}
|
| 656 |
|
| 657 |
/**
|
| 658 |
* Function retrieves release info of project off of drupal.org
|
| 659 |
* @param $project
|
| 660 |
* The drupal.org short name of the project
|
| 661 |
* @return:
|
| 662 |
* The parsed XML data or FALSE if release information couldn't be retrieved
|
| 663 |
*/
|
| 664 |
function _package_builder_release_info($project) {
|
| 665 |
$url = UPDATE_STATUS_DEFAULT_URL.'/'.$project.'/'.UPDATE_STATUS_CORE_VERSION;
|
| 666 |
$xml = drupal_http_request($url);
|
| 667 |
$parser = new update_status_xml_parser;
|
| 668 |
$data[] = $xml->data;
|
| 669 |
|
| 670 |
if ($data) {
|
| 671 |
$parsed = $parser->parse($data);
|
| 672 |
return $parsed[$project];
|
| 673 |
}
|
| 674 |
else {
|
| 675 |
return FALSE;
|
| 676 |
}
|
| 677 |
}
|
| 678 |
|
| 679 |
/**
|
| 680 |
* Function removes a project from the package_builder table
|
| 681 |
* @param $project
|
| 682 |
* The drupal.org short name of the project
|
| 683 |
* @param $notify
|
| 684 |
* If set to TRUE notifies user of the project & cached file deletion
|
| 685 |
*/
|
| 686 |
function _package_builder_remove_project($project, $notify = TRUE) {
|
| 687 |
$removed_project = db_fetch_object(db_query("SELECT * FROM {package_builder_projects} WHERE `project_name` = '%s' AND `install` IS NULL",$project));
|
| 688 |
$project_info = unserialize($removed_project->info);
|
| 689 |
db_query("DELETE FROM {package_builder_projects} WHERE `project_name` = '%s'",$removed_project->project_name);
|
| 690 |
unlink($removed_project->cache);
|
| 691 |
|
| 692 |
if ($notify) {
|
| 693 |
drupal_set_message(t("Project %project_name has been removed from included projects",array('%project_name' => $project_info['title'])));
|
| 694 |
drupal_set_message(t("Project file cache at %file_path has been removed",array('%file_path' => $removed_project->cache)));
|
| 695 |
}
|
| 696 |
}
|
| 697 |
|
| 698 |
/**
|
| 699 |
* Function retrieves a release tarball from a specified URL
|
| 700 |
* @param $url
|
| 701 |
* The URL to retrieve the tarball from
|
| 702 |
* @return:
|
| 703 |
* A string containing the file path of the tarball or FALSE if the file could
|
| 704 |
* not be retrieved.
|
| 705 |
*/
|
| 706 |
function _package_builder_retreive_project($url) {
|
| 707 |
$file_dir = variable_get('file_directory_path','files').'/package_builder/cache';
|
| 708 |
file_check_directory($file_dir, TRUE);
|
| 709 |
$file_path = $file_dir.'/'.basename($url);
|
| 710 |
$curl_handle = curl_init($url);
|
| 711 |
$new_file = @fopen($file_path, "w");
|
| 712 |
@curl_setopt($curl_handle, CURLOPT_FILE, $new_file);
|
| 713 |
@curl_setopt($curl_handle, CURLOPT_HEADER, 0);
|
| 714 |
@curl_setopt($curl_handle, CURLOPT_CONNECTTIMEOUT, 20);
|
| 715 |
$output = (@curl_exec($curl_handle)) ? $file_path : FALSE;
|
| 716 |
@fclose($new_file);
|
| 717 |
return $output;
|
| 718 |
}
|