[ Index ]

PHP Cross Reference of Drupal 6 (gatewave)

title

Body

[close]

/sites/all/modules/project/release/ -> project-release-create-history.php (source)

   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  


Generated: Thu Mar 24 11:18:33 2011 Cross-referenced by PHPXref 0.7