/**
 * Generate a list of all projects available on this server.
 */
function project_list_generate()
{
    $api_vid = _project_release_get_api_vid();
    $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");
    $xml = '';
    while ($project = db_fetch_object($query)) {
        $xml .= " <project>\n";
        $xml .= '  <title>' . check_plain($project->title) . "</title>\n";
        $xml .= '  <short_name>' . check_plain($project->uri) . "</short_name>\n";
        $xml .= '  <link>' . prch_url("node/{$project->nid}") . "</link>\n";
        $xml .= '  <dc:creator>' . check_plain($project->username) . "</dc:creator>\n";
        $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);
        $xml_terms = '';
        while ($term = db_fetch_object($term_query)) {
            $xml_terms .= '   <term><name>' . check_plain($term->vocab_name) . '</name>';
            $xml_terms .= '<value>' . check_plain($term->term_name) . "</value></term>\n";
        }
        if (!empty($xml_terms)) {
            $xml .= "  <terms>\n" . $xml_terms . "  </terms>\n";
        }
        if (!$project->status) {
            // If it's not published, we can skip the rest for this project.
            $xml .= "  <project_status>unpublished</project_status>\n";
        } else {
            $xml .= "  <project_status>published</project_status>\n";
            // Include a list of API terms if available.
            $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);
            $xml_api_terms = '';
            while ($api_term = db_fetch_object($term_query)) {
                $xml_api_terms .= '   <api_version>' . check_plain($api_term->term_name) . "</api_version>\n";
            }
            if (!empty($xml_api_terms)) {
                $xml .= "  <api_versions>\n" . $xml_api_terms . "  </api_versions>\n";
            }
        }
        $xml .= " </project>\n";
    }
    if (empty($xml)) {
        wd_err(array('message' => 'No projects found on this server.'));
        return FALSE;
    }
    project_release_history_write_xml($xml);
}
/**
 * Update the DB with the new file info for a given release node.
 *
 * @todo This assumes 1:1 relationship of release nodes to files.
 */
function package_release_update_node($nid, $file_path)
{
    global $dest_root, $task;
    $full_path = $dest_root . '/' . $file_path;
    // PHP will cache the results of stat() and give us stale answers
    // here, unless we manually tell it otherwise!
    clearstatcache();
    // Now that we have the official file, compute some metadata:
    $file_name = basename($file_path);
    $file_date = filemtime($full_path);
    $file_size = filesize($full_path);
    $file_hash = md5_file($full_path);
    $file_mime = file_get_mimetype($full_path);
    $uid = db_result(db_query("SELECT n.uid FROM {node} n WHERE n.nid = %d", $nid));
    // Finally, save this file to the DB.
    // First, see if we already have a file for this release node
    $file_data = db_fetch_object(db_query("SELECT * FROM {project_release_file} WHERE nid = %d  GROUP BY nid ORDER BY fid DESC", $nid));
    if (empty($file_data)) {
        // Don't have an file data for this release, insert a new record.
        db_query("INSERT INTO {files} (uid, filename, filepath, filemime, filesize, status, timestamp) VALUES (%d, '%s', '%s', '%s', %d, %d, %d)", $uid, $file_name, $file_path, $file_mime, $file_size, FILE_STATUS_PERMANENT, $file_date);
        $fid = db_last_insert_id('files', 'fid');
        db_query("INSERT INTO {project_release_file} (fid, nid, filehash) VALUES (%d, %d, '%s')", $fid, $nid, $file_hash);
    } else {
        // Already have a file for this release, update it.
        db_query("UPDATE {files} SET uid = %d, filename = '%s', filepath = '%s', filemime = '%s', filesize = %d, status = %d, timestamp = %d WHERE fid = %d", $uid, $file_name, $file_path, $file_mime, $file_size, FILE_STATUS_PERMANENT, $file_date, $file_data->fid);
        db_query("UPDATE {project_release_file} SET filehash = '%s' WHERE fid = %d", $file_hash, $file_data->fid);
    }
    // Don't auto-publish security updates.
    if ($task == 'tag' && db_result(db_query("SELECT COUNT(*) FROM {term_node} WHERE nid = %d AND tid = %d", $nid, SECURITY_UPDATE_TID))) {
        watchdog('package_security', "Not auto-publishing security update release.", array(), WATCHDOG_NOTICE, l(t('view'), 'node/' . $nid));
        return;
    }
    // Finally publish the node if it is currently unpublished.  Instead of
    // directly updating {node}.status, we use node_save() so that other modules
    // which implement hook_nodeapi() will know that this node is now published.
    // However, we don't want to waste too much RAM by leaving all these loaded
    // nodes in RAM, so we reset the node_load() cache each time we call it.
    $status = db_result(db_query("SELECT status from {node} WHERE nid = %d", $nid));
    if (empty($status)) {
        // If the site is using DB replication, force this node_load() to use the
        // primary database to avoid node_load() failures.
        if (function_exists('db_set_ignore_slave')) {
            db_set_ignore_slave();
        }
        $node = node_load($nid, NULL, TRUE);
        if (!empty($node->nid)) {
            $node->status = 1;
            node_save($node);
        } else {
            wd_err('node_load(@nid) failed', array('@nid' => $nid));
        }
    }
}
/**
 * Update the DB with the new file info for a given release node.
 *
 * @param $nid
 *   The node ID of the release node to update.
 * @param $files
 *   Array of files to add to the release node.
 * @param $package_contents
 *   Optional. Array of nids of releases contained in a release package.
 */
function package_release_update_node($nid, $files, $package_contents = array())
{
    global $drupal_root, $dest_root, $task;
    // PHP will cache the results of stat() and give us stale answers
    // here, unless we manually tell it otherwise!
    clearstatcache();
    // Make sure we're back at the webroot so node_load() and node_save()
    // can always find any files they (and the hooks they invoke) need.
    if (!drupal_chdir($drupal_root)) {
        return FALSE;
    }
    // If the site is using DB replication, force this node_load() to use the
    // primary database to avoid node_load() failures.
    if (function_exists('db_set_ignore_slave')) {
        db_set_ignore_slave();
    }
    // We don't want to waste too much RAM by leaving all these loaded nodes
    // in RAM, so we reset the node_load() cache each time we call it.
    $node = node_load($nid, NULL, TRUE);
    if (empty($node->nid)) {
        wd_err('node_load(@nid) failed', array('@nid' => $nid));
        return FALSE;
    }
    foreach ($files as $file_path) {
        // Compute the metadata for this file that we care about.
        $full_path = $dest_root . '/' . $file_path;
        $file_name = basename($file_path);
        $file_date = filemtime($full_path);
        $file_size = filesize($full_path);
        $file_hash = md5_file($full_path);
        $file_mime = file_get_mimetype($full_path);
        // First, see if we already have this file for this release node
        $file_data = db_fetch_object(db_query("SELECT prf.* FROM {project_release_file} prf INNER JOIN {files} f ON prf.fid = f.fid WHERE prf.nid = %d AND f.filename = '%s'", $node->nid, $file_name));
        // Insert or update the record in the DB as need.
        if (empty($file_data)) {
            // Don't have this file, insert a new record.
            db_query("INSERT INTO {files} (uid, filename, filepath, filemime, filesize, status, timestamp) VALUES (%d, '%s', '%s', '%s', %d, %d, %d)", $node->uid, $file_name, $file_path, $file_mime, $file_size, FILE_STATUS_PERMANENT, $file_date);
            $fid = db_last_insert_id('files', 'fid');
            db_query("INSERT INTO {project_release_file} (fid, nid, filehash) VALUES (%d, %d, '%s')", $fid, $node->nid, $file_hash);
        } else {
            // Already have this file for this release, update it.
            db_query("UPDATE {files} SET uid = %d, filename = '%s', filepath = '%s', filemime = '%s', filesize = %d, status = %d, timestamp = %d WHERE fid = %d", $node->uid, $file_name, $file_path, $file_mime, $file_size, FILE_STATUS_PERMANENT, $file_date, $file_data->fid);
            db_query("UPDATE {project_release_file} SET filehash = '%s' WHERE fid = %d", $file_hash, $file_data->fid);
        }
    }
    // Store package contents if necessary.
    if (!empty($package_contents) && module_exists('project_package')) {
        foreach ($package_contents as $item_nid) {
            db_query("INSERT INTO {project_package_local_release_item} (package_nid, item_nid) VALUES (%d, %d)", $nid, $item_nid);
        }
    }
    // Don't auto-publish security updates.
    $security_update_tid = variable_get('project_release_security_update_tid', 0);
    if ($task == 'tag' && !empty($node->taxonomy[$security_update_tid])) {
        watchdog('package_security', 'Not auto-publishing security update release.', array(), WATCHDOG_NOTICE, l(t('view'), 'node/' . $node->nid));
        return;
    }
    // Finally publish the node if it is currently unpublished. Instead of
    // directly updating {node}.status, we use node_save() so that other modules
    // which implement hook_nodeapi() will know that this node is now published.
    if (empty($node->status)) {
        $node->status = 1;
        node_save($node);
    }
}
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_SERVER['REQUEST_URI'] = '/' . $script_name;
$_SERVER['SCRIPT_NAME'] = '/' . $script_name;
$_SERVER['PHP_SELF'] = '/' . $script_name;
$_SERVER['SCRIPT_FILENAME'] = $_SERVER['PWD'] . '/' . $script_name;
$_SERVER['PATH_TRANSLATED'] = $_SERVER['SCRIPT_FILENAME'];
if (!chdir(DRUPAL_ROOT)) {
    print "ERROR: Can't chdir(DRUPAL_ROOT), aborting.\n";
    exit(1);
}
// Make sure our umask is sane for generating directories and files.
umask(022);
require_once 'includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
if (!module_exists('project_usage')) {
    wd_err(t("ERROR: Project usage module does not exist, aborting.\n"));
    exit(1);
}
// Load the API functions we need for manipulating dates and timestamps.
module_load_include('inc', 'project_usage', 'includes/date_api');
// ------------------------------------------------------------
// Call the daily and weekly processing tasks as needed.
// ------------------------------------------------------------
$now = time();
// Figure out if it's been 24 hours since our last daily processing.
if (variable_get('project_usage_last_daily', 0) <= $now - PROJECT_USAGE_DAY) {
    project_usage_process_daily();
    variable_set('project_usage_last_daily', $now);
}
// We can't process the weekly data until the week has completed. To see if
// there's data available: determine the last time we completed the weekly
/**
 * Initialize the tmp directory. Use different subdirs for building
 * snapshots than official tags, so there's no potential directory
 * collisions and race conditions if both are running at the same time
 * (due to how long it takes to complete a branch snapshot run, and
 * how often we run this for tag-based releases).
 */
function initialize_tmp_dir($task)
{
    global $tmp_dir, $tmp_root, $rm;
    if (!is_dir($tmp_root) && !@mkdir($tmp_root, 0777, TRUE)) {
        wd_err("ERROR: mkdir(@dir) (tmp_root) failed", array('@dir' => $tmp_root));
        exit(1);
    }
    // Use a tmp directory *specific* to this invocation, so that we don't
    // clobber other runs if the script is invoked twice (e.g. via cron and
    // manually, etc).
    $tmp_dir = $tmp_root . '/' . $task . '.' . getmypid();
    if (is_dir($tmp_dir)) {
        // Make sure we start with a clean slate
        drupal_exec("{$rm} -rf {$tmp_dir}/*");
    } else {
        if (!@mkdir($tmp_dir, 0777, TRUE)) {
            wd_err("ERROR: mkdir(@dir) failed", array('@dir' => $tmp_dir));
            exit(1);
        }
    }
}