| [ Index ] |
PHP Cross Reference of Drupal 6 (gatewave) |
[Summary view] [Print] [Text view]
1 #!/usr/bin/php 2 <?php 3 4 // $Id: project-release-create-history.php,v 1.29 2010/01/17 00:00:11 dww Exp $ 5 6 /** 7 * @file 8 * Dumps out a complete history of releases for a given project. Each 9 * file is an XML representation of all relevant release data for 10 * update status checking, security notification, etc. Every project 11 * creates a separate file for the releases for each unique API 12 * compatibility term (e.g. for Drupal: 5.x, 6.x, etc). 13 * 14 * @author Derek Wright (http://drupal.org/user/46549) 15 * 16 */ 17 18 // ------------------------------------------------------------ 19 // Required customization 20 // ------------------------------------------------------------ 21 22 // Root of the directory tree for the XML history files. 23 define('HISTORY_ROOT', ''); 24 25 // The root of your Drupal installation, so we can properly bootstrap 26 // Drupal. This should be the full path to the directory that holds 27 // your index.php file, the "includes" subdirectory, etc. 28 define('DRUPAL_ROOT', ''); 29 30 // The name of your site. Required so that when we bootstrap Drupal in 31 // this script, we find the right settings.php file in your sites folder. 32 define('SITE_NAME', ''); 33 34 35 // ------------------------------------------------------------ 36 // Initialization 37 // (Real work begins here, nothing else to customize) 38 // ------------------------------------------------------------ 39 40 // Check if all required variables are defined 41 $vars = array( 42 'DRUPAL_ROOT' => DRUPAL_ROOT, 43 'SITE_NAME' => SITE_NAME, 44 ); 45 $fatal_err = FALSE; 46 foreach ($vars as $name => $val) { 47 if (empty($val)) { 48 print "ERROR: \"$name\" constant not defined, aborting\n"; 49 $fatal_err = TRUE; 50 } 51 } 52 if ($fatal_err) { 53 exit(1); 54 } 55 56 $script_name = $argv[0]; 57 58 // See if we're being restricted to a single project. 59 $project_id = 0; 60 if (!empty($argv[1])) { 61 $project_id = $argv[1]; 62 } 63 64 // Setup variables for Drupal bootstrap 65 $_SERVER['HTTP_HOST'] = SITE_NAME; 66 $_SERVER['REMOTE_ADDR'] = '127.0.0.1'; 67 $_SERVER['REQUEST_URI'] = '/' . $script_name; 68 $_SERVER['SCRIPT_NAME'] = '/' . $script_name; 69 $_SERVER['PHP_SELF'] = '/' . $script_name; 70 $_SERVER['SCRIPT_FILENAME'] = $_SERVER['PWD'] .'/'. $script_name; 71 $_SERVER['PATH_TRANSLATED'] = $_SERVER['SCRIPT_FILENAME']; 72 73 if (!chdir(DRUPAL_ROOT)) { 74 print "ERROR: Can't chdir(DRUPAL_ROOT), aborting.\n"; 75 exit(1); 76 } 77 // Make sure our umask is sane for generating directories and files. 78 umask(022); 79 80 require_once 'includes/bootstrap.inc'; 81 drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); 82 83 if (!is_dir(HISTORY_ROOT)) { 84 if (!mkdir(HISTORY_ROOT)) { 85 wd_err(array('message' => "ERROR: Could not create history directory (%directory).\n", 'args' => array('%directory' => HISTORY_ROOT))); 86 exit(1); 87 } 88 } 89 90 project_release_history_generate_all($project_id); 91 if (empty($project_id)) { 92 // If we're operating on all projects, generate the huge list, too. 93 project_list_generate(); 94 } 95 96 97 // ------------------------------------------------------------ 98 // Functions: main work 99 // ------------------------------------------------------------ 100 101 /** 102 * Figure out what project and API terms to generate the history for. 103 */ 104 function project_release_history_generate_all($project_id = 0) { 105 if (!empty($project_id)) { 106 if (is_numeric($project_id)) { 107 $project_nid = $project_id; 108 } 109 else { 110 $project_nid = db_result(db_query("SELECT nid FROM {project_projects} WHERE uri = '%s'", $project_id)); 111 } 112 if (empty($project_nid)) { 113 wd_err(array('message' => 'Project ID %id not found', 'args' => array('%id' => $project_id))); 114 return FALSE; 115 } 116 wd_msg(array('message' => 'Generating XML release history files for project: %id.', 'args' => array('%id' => $project_id))); 117 } 118 else { 119 wd_msg(array('message' => 'Generating XML release history files for all projects.', 'args' => array())); 120 } 121 122 $api_terms = project_release_compatibility_list(); 123 124 $i = 0; 125 if (empty($project_nid)) { 126 // Generate all.xml files for projects with releases. 127 $query = db_query("SELECT DISTINCT(pid) FROM {project_release_nodes}"); 128 while ($project = db_fetch_object($query)) { 129 project_release_history_generate_project_xml($project->pid); 130 $i++; 131 } 132 } 133 else { 134 project_release_history_generate_project_xml($project_nid); 135 $i++; 136 } 137 138 if ($i == 1) { 139 wd_msg(array('message' => 'Generated an XML release history summary for a project.')); 140 } 141 else { 142 wd_msg(array('message' => 'Generated XML release history summaries for @count projects.', 'args' => array('@count' => $i))); 143 } 144 145 // Generate XML files based on API compatibility. 146 $i = 0; 147 $args = array_keys($api_terms); 148 $placeholders = db_placeholders($args); 149 $where = ''; 150 if (!empty($project_nid)) { 151 $args[] = $project_nid; 152 $where = 'AND pid = %d'; 153 } 154 $query = db_query("SELECT DISTINCT(pid), version_api_tid FROM {project_release_nodes} WHERE version_api_tid IN ($placeholders) $where", $args); 155 while ($project = db_fetch_object($query)) { 156 project_release_history_generate_project_xml($project->pid, $project->version_api_tid); 157 $i++; 158 } 159 if ($i == 1) { 160 wd_msg(array('message' => 'Completed XML release history files for 1 project/version pair')); 161 } 162 else { 163 wd_msg(array('message' => 'Completed XML release history files for @count project/version pairs', 'args' => array('@count' => $i))); 164 } 165 } 166 167 /** 168 * Generate the XML history file for a given project name and API 169 * compatibility term. 170 * 171 * @todo If a history file already exists for this combination, this 172 * function will generate a new history and atomically replace the old 173 * one (currently, just logs to watchdog for debugging). 174 * 175 * @todo If there's no subdirectory in the directory tree for this 176 * project yet, this function creates one. 177 * 178 * @param $project_nid 179 * Project ID (node id of the project node) to generate history for. 180 * @param $api_tid 181 * Taxonomy id (tid) of the API compatibility term to use, or NULL if 182 * all terms are considered. 183 */ 184 function project_release_history_generate_project_xml($project_nid, $api_tid = NULL) { 185 $api_vid = _project_release_get_api_vid(); 186 187 if (isset($api_tid)) { 188 // Restrict output to a specific API compatibility term. 189 $api_terms = project_release_compatibility_list(); 190 if (!isset($api_terms[$api_tid])) { 191 wd_err(array('message' => 'API compatibility term %tid not found.', 'args' => array('%tid' => $api_tid))); 192 return FALSE; 193 } 194 $api_version = $api_terms[$api_tid]; 195 196 // Get project-wide data: 197 $sql = "SELECT DISTINCT n.title, n.nid, n.vid, n.status, p.uri, u.name AS username FROM {node} n INNER JOIN {project_projects} p ON n.nid = p.nid INNER JOIN {project_release_supported_versions} prsv ON prsv.nid = n.nid INNER JOIN {users} u ON n.uid = u.uid WHERE prsv.tid = %d AND prsv.nid = %d"; 198 $query = db_query($sql, $api_tid, $project_nid); 199 } 200 else { 201 // Consider all API compatibility terms. 202 $api_version = 'all'; 203 $sql = "SELECT n.title, n.nid, n.vid, n.status, p.uri, u.name AS username FROM {node} n INNER JOIN {project_projects} p ON n.nid = p.nid INNER JOIN {users} u ON n.uid = u.uid WHERE p.nid = %d"; 204 $query = db_query($sql, $project_nid); 205 } 206 207 $project = db_fetch_object($query); 208 if (empty($project)) { 209 if (empty($api_tid)) { 210 wd_err(array('message' => 'Project ID @pid not found', 'args' => array('@pid' => $project_nid))); 211 } 212 else { 213 wd_err(array('message' => 'Project ID @pid has no supported releases for API term ID @api_tid', 'args' => array('@pid' => $project_nid, '@api_tid' => $api_tid))); 214 return FALSE; 215 } 216 } 217 218 $xml = '<title>'. check_plain($project->title) ."</title>\n"; 219 $xml .= '<short_name>'. check_plain($project->uri) ."</short_name>\n"; 220 $xml .= '<dc:creator>'. check_plain($project->username) ."</dc:creator>\n"; 221 $xml .= '<api_version>'. check_plain($api_version) ."</api_version>\n"; 222 if (!$project->status) { 223 // If it's not published, we can skip the rest of this and bail. 224 $xml .= "<project_status>unpublished</project_status>\n"; 225 project_release_history_write_xml($xml, $project, $api_version); 226 return; 227 } 228 229 $project_status = 'published'; 230 if (isset($api_tid)) { 231 // Include the info about supported and recommended major versions. 232 $query = db_query("SELECT major, supported, recommended FROM {project_release_supported_versions} WHERE nid = %d AND tid = %d", $project_nid, $api_tid); 233 $supported_majors = array(); 234 while ($version_info = db_fetch_object($query)) { 235 if ($version_info->supported) { 236 $supported_majors[] = $version_info->major; 237 } 238 if ($version_info->recommended) { 239 $recommended_major = $version_info->major; 240 } 241 } 242 if (isset($recommended_major)) { 243 $xml .= '<recommended_major>'. $recommended_major ."</recommended_major>\n"; 244 } 245 if (empty($supported_majors)) { 246 $project_status = 'unsupported'; 247 } 248 else { 249 $xml .= '<supported_majors>'. implode(',', $supported_majors) ."</supported_majors>\n"; 250 // To avoid confusing existing clients, include <default_major>, too. 251 $xml .= '<default_major>'. min($supported_majors) ."</default_major>\n"; 252 } 253 } 254 255 $xml .= '<project_status>'. $project_status ."</project_status>\n"; 256 $xml .= '<link>'. prch_url("node/$project->nid") ."</link>\n"; 257 258 // To prevent the update(_status) module from having problems parsing the XML, 259 // the terms need to be at the end of the information for the project. 260 $term_query = db_query("SELECT v.name AS vocab_name, v.vid, td.name AS term_name, td.tid FROM {term_node} tn INNER JOIN {term_data} td ON tn.tid = td.tid INNER JOIN {vocabulary} v ON td.vid = v.vid WHERE tn.vid = %d", $project->vid); 261 $xml_terms = ''; 262 while ($term = db_fetch_object($term_query)) { 263 $xml_terms .= ' <term><name>'. check_plain($term->vocab_name) .'</name>'; 264 $xml_terms .= '<value>'. check_plain($term->term_name) ."</value></term>\n"; 265 } 266 if (!empty($xml_terms)) { 267 $xml .= " <terms>\n". $xml_terms ." </terms>\n"; 268 } 269 270 // Now, build the query for all the releases for this project and term. 271 $joins = array(); 272 $where = array(); 273 $parameters = array(); 274 // TODO: This is broken for N files per release node. 275 $fields = array( 276 'n.nid', 277 'n.vid', 278 'f.filepath', 279 'f.filesize', 280 'f.timestamp', 281 'prf.filehash', 282 'prn.rebuild', 283 'prn.version', 284 'prn.version_major', 285 'prn.version_minor', 286 'prn.version_patch', 287 'prn.version_extra', 288 'prn.tag', 289 'n.title', 290 'n.status', 291 ); 292 293 $joins[] = "INNER JOIN {project_release_nodes} prn ON n.nid = prn.nid"; 294 $joins[] = "INNER JOIN {project_release_file} prf ON n.nid = prf.nid"; 295 $joins[] = "INNER JOIN {files} f ON prf.fid = f.fid"; 296 $where[] = "prn.pid = '%d'"; 297 $parameters[] = $project->nid; 298 299 // Restrict releases to the specified API version. 300 if (isset($api_tid)) { 301 $where[] = 'prn.version_api_tid = %d'; 302 $parameters[] = $api_tid; 303 } 304 else { 305 // If we're building a list for all versions, then we also need to sort 306 // our releases based on the API term's weight. 307 $joins[] = "INNER JOIN {term_data} td ON prn.version_api_tid = td.tid"; 308 $fields[] = 'td.weight'; 309 } 310 311 $query = "SELECT ". implode(', ', $fields) ." FROM {node} n "; 312 $query .= implode(' ', $joins); 313 $query .= " WHERE " . implode(' AND ', $where); 314 $result = db_query($query, $parameters); 315 316 $releases = array(); 317 while ($release = db_fetch_object($result)) { 318 $releases[] = $release; 319 } 320 321 if (empty($releases)) { 322 // Nothing more to include for this project, wrap up and return. 323 project_release_history_write_xml($xml, $project, $api_version); 324 return; 325 } 326 327 // Sort the releases based on our custom sorting function. 328 usort($releases, "_release_sort"); 329 330 $xml .= "<releases>\n"; 331 foreach ($releases as $release) { 332 $xml .= " <release>\n"; 333 $xml .= ' <name>'. check_plain($release->title) ."</name>\n"; 334 $xml .= ' <version>'. check_plain($release->version) ."</version>\n"; 335 if (!empty($release->tag) && $tag = check_plain($release->tag)) { 336 $xml .= ' <tag>'. $tag ."</tag>\n"; 337 } 338 foreach (array('major', 'minor', 'patch', 'extra') as $type) { 339 $vers_type = "version_$type"; 340 if (isset($release->$vers_type)) { 341 $xml .= " <$vers_type>". check_plain($release->$vers_type) ."</$vers_type>\n"; 342 } 343 } 344 if ($release->status) { 345 // Published, so we should include the links. 346 $xml .= " <status>published</status>\n"; 347 $xml .= ' <release_link>'. prch_url("node/$release->nid") ."</release_link>\n"; 348 if (!empty($release->filepath)) { 349 $download_link = theme('project_release_download_link', $release->filepath, NULL, TRUE); 350 $xml .= ' <download_link>'. $download_link['href'] ."</download_link>\n"; 351 } 352 } 353 else { 354 $xml .= " <status>unpublished</status>\n"; 355 } 356 // We want to include the rest of these regardless of the status. 357 if (!empty($release->timestamp)) { 358 $xml .= ' <date>'. check_plain($release->timestamp) ."</date>\n"; 359 } 360 if (!empty($release->filehash)) { 361 $xml .= ' <mdhash>'. check_plain($release->filehash) ."</mdhash>\n"; 362 } 363 if (isset($release->filesize)) { 364 $xml .= ' <filesize>'. check_plain($release->filesize) ."</filesize>\n"; 365 } 366 $term_query = db_query("SELECT v.name AS vocab_name, v.vid, td.name AS term_name, td.tid FROM {term_node} tn INNER JOIN {term_data} td ON tn.tid = td.tid INNER JOIN {vocabulary} v ON td.vid = v.vid WHERE tn.vid = %d AND v.vid != %d", $release->vid, $api_vid); 367 $xml_terms = ''; 368 while ($term = db_fetch_object($term_query)) { 369 $xml_terms .= ' <term><name>'. check_plain($term->vocab_name) .'</name>'; 370 $xml_terms .= '<value>'. check_plain($term->term_name) ."</value></term>\n"; 371 } 372 if (!empty($xml_terms)) { 373 $xml .= " <terms>\n". $xml_terms ." </terms>\n"; 374 } 375 $xml .= " </release>\n"; 376 } 377 $xml .= "</releases>\n"; 378 project_release_history_write_xml($xml, $project, $api_version); 379 } 380 381 382 /** 383 * Write out the XML history for a given project and version to a file. 384 * 385 * @param $xml 386 * String containing the XML representation of the history. 387 * @param $project 388 * An object containing (at least) the title and uri of project. 389 * @param $api_version 390 * The API compatibility version the history is for. 391 */ 392 function project_release_history_write_xml($xml, $project = NULL, $api_version = NULL) { 393 394 // Dublin core namespace according to http://dublincore.org/documents/dcmi-namespace/ 395 $dc_namespace = 'xmlns:dc="http://purl.org/dc/elements/1.1/"'; 396 if (!isset($project)) { 397 // We are outputting a global project list. 398 $project_dir = HISTORY_ROOT .'/project-list'; 399 $filename = $project_dir .'/project-list-all.xml'; 400 $tmp_filename = $filename .'.new'; 401 $errors = array( 402 'mkdir' => array( 403 'message' => 'ERROR: mkdir(@dir) failed, cannot write project list.', 404 'args' => array('@dir' => $project_dir), 405 ), 406 'unlink' => array( 407 'message' => 'ERROR: unlink(@file) failed, cannot write project list.', 408 'args' => array('@file' => $tmp_filename), 409 ), 410 'rename' => array( 411 'message' => 'ERROR: rename(@old, @new) failed, cannot write project list.', 412 'args' => array('@old' => $tmp_filename, '@new' => $filename), 413 ), 414 ); 415 $full_xml = '<?xml version="1.0" encoding="utf-8"?>' . "\n"; 416 $full_xml .= '<projects '. $dc_namespace .">\n" . $xml . "</projects>\n"; 417 } 418 else { 419 // Setup the filenames we'll be using. Normally, we'd have to be 420 // extra careful with $project->uri to avoid malice here, however, 421 // that's validated on the project edit form to prevent any funny 422 // characters, so that much is safe. The rest of these paths are 423 // just from the global variables at the top of this script, so we 424 // can trust those. The only one we should be careful of is the 425 // taxonomy term for the API compatibility. 426 $safe_api_vers = strtr($api_version, '/', '_'); 427 $project_dir = HISTORY_ROOT .'/'. $project->uri; 428 $project_id = $project->uri .'-'. $safe_api_vers .'.xml'; 429 $filename = $project_dir .'/'. $project_id; 430 $tmp_filename = $filename .'.new'; 431 $errors = array( 432 'mkdir' => array( 433 'message' => "ERROR: mkdir(@dir) failed, can't write history for %project.", 434 'args' => array('@dir' => $project_dir, '%project' => $project->title), 435 ), 436 'unlink' => array( 437 'message' => "ERROR: unlink(@file) failed, can't write history for %project.", 438 'args' => array('@file' => $tmp_filename, '%project' => $project->title), 439 ), 440 'rename' => array( 441 'message' => "ERROR: rename(@old, @new) failed, can't write history for %project.", 442 'args' => array('@old' => $tmp_filename, '@new' => $filename, '%project' => $project->title), 443 ), 444 ); 445 $full_xml = '<?xml version="1.0" encoding="utf-8"?>' . "\n"; 446 $full_xml .= '<project '. $dc_namespace .">\n" . $xml . "</project>\n"; 447 } 448 449 // Make sure we've got the right project-specific subdirectory. 450 if (!is_dir($project_dir) && !mkdir($project_dir)) { 451 wd_err($errors['mkdir']); 452 return FALSE; 453 } 454 // Make sure the "[project]-[version].xml.new" file doesn't exist. 455 if (is_file($tmp_filename) && !unlink($tmp_filename)) { 456 wd_err($errors['unlink']); 457 return FALSE; 458 } 459 // Write the XML history to "[project]-[version].xml.new". 460 if (!$hist_fd = fopen($tmp_filename, 'xb')) { 461 wd_err(array('message' => "ERROR: fopen(@file, 'xb') failed", 'args' => array('@file' => $tmp_filename))); 462 return FALSE; 463 } 464 if (!fwrite($hist_fd, $full_xml)) { 465 wd_err(array('message' => "ERROR: fwrite(@file) failed" . '<pre>' . check_plain($full_xml), 'args' => array('@file' => $tmp_filename))); 466 return FALSE; 467 } 468 // We have to close this handle before we can rename(). 469 fclose($hist_fd); 470 471 // Now we can atomically rename the .new into place in the "live" spot. 472 if (!_rename($tmp_filename, $filename)) { 473 wd_err($errors['rename']); 474 return FALSE; 475 } 476 return TRUE; 477 } 478 479 /** 480 * Generate a list of all projects available on this server. 481 */ 482 function project_list_generate() { 483 $api_vid = _project_release_get_api_vid(); 484 485 $query = db_query("SELECT n.title, n.nid, n.vid, n.status, p.uri, u.name AS username FROM {node} n INNER JOIN {project_projects} p ON n.nid = p.nid INNER JOIN {users} u ON n.uid = u.uid"); 486 487 $xml = ''; 488 while ($project = db_fetch_object($query)) { 489 $xml .= " <project>\n"; 490 $xml .= ' <title>'. check_plain($project->title) ."</title>\n"; 491 $xml .= ' <short_name>'. check_plain($project->uri) ."</short_name>\n"; 492 $xml .= ' <link>'. prch_url("node/$project->nid") ."</link>\n"; 493 $xml .= ' <dc:creator>'. check_plain($project->username). "</dc:creator>\n"; 494 $term_query = db_query("SELECT v.name AS vocab_name, v.vid, td.name AS term_name, td.tid FROM {term_node} tn INNER JOIN {term_data} td ON tn.tid = td.tid INNER JOIN {vocabulary} v ON td.vid = v.vid WHERE tn.vid = %d", $project->vid); 495 $xml_terms = ''; 496 while ($term = db_fetch_object($term_query)) { 497 $xml_terms .= ' <term><name>'. check_plain($term->vocab_name) .'</name>'; 498 $xml_terms .= '<value>'. check_plain($term->term_name) ."</value></term>\n"; 499 } 500 if (!empty($xml_terms)) { 501 $xml .= " <terms>\n". $xml_terms ." </terms>\n"; 502 } 503 if (!$project->status) { 504 // If it's not published, we can skip the rest for this project. 505 $xml .= " <project_status>unpublished</project_status>\n"; 506 } 507 else { 508 $xml .= " <project_status>published</project_status>\n"; 509 // Include a list of API terms if available. 510 $term_query = db_query("SELECT DISTINCT(td.tid), td.name AS term_name FROM {project_release_nodes} prn INNER JOIN {term_data} td ON prn.version_api_tid = td.tid WHERE prn.pid = %d AND td.vid = %d ORDER BY td.weight ASC", $project->nid, $api_vid); 511 $xml_api_terms = ''; 512 while ($api_term = db_fetch_object($term_query)) { 513 $xml_api_terms .= ' <api_version>'. check_plain($api_term->term_name) ."</api_version>\n"; 514 } 515 if (!empty($xml_api_terms)) { 516 $xml .= " <api_versions>\n". $xml_api_terms ." </api_versions>\n"; 517 } 518 } 519 520 $xml .= " </project>\n"; 521 } 522 if (empty($xml)) { 523 wd_err(array('message' => 'No projects found on this server.')); 524 return FALSE; 525 } 526 project_release_history_write_xml($xml); 527 } 528 529 // ------------------------------------------------------------ 530 // Functions: utility methods 531 // ------------------------------------------------------------ 532 533 /** 534 * Wrapper function for watchdog() to log notice messages. 535 * 536 * @param $notice 537 * An associative array with 'message' and 'args' keys for the notice message 538 * and any arguments respectively. 539 * @param $link 540 * A link to associate with the message. 541 */ 542 function wd_msg($notice, $link = NULL) { 543 watchdog('release_history', $notice['message'], $notice['args'], WATCHDOG_NOTICE, $link); 544 } 545 546 /** 547 * Wrapper function for watchdog() to log error messages. 548 * 549 * @param $error 550 * An associative array with 'message' and 'args' keys for the error message 551 * and any arguments respectively. 552 * @param $link 553 * A link to associate with the message. 554 */ 555 function wd_err($error, $link = NULL) { 556 watchdog('release_hist_err', $error['message'], $error['args'], WATCHDOG_ERROR, $link); 557 } 558 559 /** 560 * Rename on Windows isn't atomic like it is on *nix systems. 561 * See http://www.php.net/rename about this bug. 562 */ 563 function _rename($oldfile, $newfile) { 564 if (substr(PHP_OS, 0, 3) == 'WIN') { 565 if (copy($oldfile, $newfile)) { 566 unlink($oldfile); 567 return TRUE; 568 } 569 return FALSE; 570 } 571 else { 572 return rename($oldfile, $newfile); 573 } 574 } 575 576 /** 577 * Sorting function to ensure releases are in the right order in the XML file. 578 * 579 * Loop over the fields in the release node we care about, and the first field 580 * that differs between the two releases determines the order. 581 * 582 * We first check the 'weight' (of the API version term) for when we're 583 * building a single list of all versions, not a per-API version listing. In 584 * this case, lower numbers should float to the top. 585 * 586 * We also need to special-case the 'rebuild' field, which is how we know if 587 * it's a dev snapshot or official release. Rebuild == 1 should always come 588 * last within a given major version, since that's how update_status expects 589 * the ordering to ensure that we never recommend a -dev release if there's an 590 * official release available. So, like weight, the lower number for 'rebuild' 591 * should float to the top. 592 * 593 * For every other field, we want the bigger numbers come first. 594 * 595 * @see project_release_history_generate_project_xml() 596 * @see usort() 597 */ 598 function _release_sort($a, $b) { 599 // This array maps fields in the release node to the sort order, where -1 600 // means to sort like Drupal weights, and +1 means the bigger numbers are 601 // higher in the listing. 602 $fields = array( 603 'weight' => -1, 604 'version_major' => 1, 605 'rebuild' => -1, 606 'version_minor' => 1, 607 'version_patch' => 1, 608 'timestamp' => 1, 609 ); 610 foreach ($fields as $field => $sign) { 611 if (!isset($a->$field) && !isset($b->$field)) { 612 continue; 613 } 614 if ($a->$field == $b->$field) { 615 continue; 616 } 617 return ($a->$field < $b->$field) ? $sign : (-1 * $sign); 618 } 619 } 620 621 /** 622 * Helper function to generate clean absolute links for the XML files. 623 * 624 * Relying on core's url() gives us crazy results when the script is invoked 625 * with a full path, since the construction of $base_url during bootstrapping 626 * is all wrong. 627 * 628 * @todo This doesn't handle sites installed in subdirectories that actually 629 * define their own $base_url in settings.php... 630 */ 631 function prch_url($path) { 632 static $base_url = NULL; 633 static $clean_url = NULL; 634 if (!isset($clean_url)) { 635 $clean_url = (bool)variable_get('clean_url', '0'); 636 } 637 638 if (!isset($base_url)) { 639 $base_root = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https' : 'http'; 640 $base_url = $base_root .= '://'. $_SERVER['HTTP_HOST'] .'/'; 641 } 642 643 $path = drupal_get_path_alias($path, ''); 644 if ($clean_url) { 645 return $base_url . $path; 646 } 647 else { 648 return $base_url .'?q='. $path; 649 } 650 } 651
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Mar 24 11:18:33 2011 | Cross-referenced by PHPXref 0.7 |