cvs diff: Diffing modules/project Index: modules/project/CHANGELOG.txt =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/project/CHANGELOG.txt,v retrieving revision 1.5.2.1 diff -u -F^f -r1.5.2.1 CHANGELOG.txt --- modules/project/CHANGELOG.txt 25 Jul 2006 00:12:26 -0000 1.5.2.1 +++ modules/project/CHANGELOG.txt 10 Sep 2006 19:51:02 -0000 @@ -1,3 +1,8 @@ +XX. September 2006 +----------------- +- Split out releases into project_release.module and made them real nodes + (dww and merlinofchaos) + 21. July 2006 ----------------- - Split out issue tracking to project_issue.module (dww) Index: modules/project/project.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/project/project.inc,v retrieving revision 1.75.2.16 diff -u -F^f -r1.75.2.16 project.inc --- modules/project/project.inc 26 Jul 2006 07:18:01 -0000 1.75.2.16 +++ modules/project/project.inc 10 Sep 2006 19:51:03 -0000 @@ -173,7 +173,7 @@ function project_project_form(&$node) { '#description' => t('Link to a live demo.'), ); - if ($releases = project_release_load($node)) { + if ($releases = project_release_get_releases($node, false)) { $form['project']['version'] = array( '#type' => 'select', '#title' => t('Default version'), @@ -303,31 +303,34 @@ function project_project_view(&$node, $t $breadcrumb = project_project_set_location($node, $breadcrumb); menu_set_location($breadcrumb); - if ($releases = project_release_load($node)) { + $releases = project_release_get_releases($node); + if ($releases) { // Determine most suitable release $overview = variable_get('project_release_overview', -1); - foreach ($releases as $rid => $version) { + foreach ($releases as $rid => $release) { // If the project has a preferred release, choose that. + $version = theme('project_release_version', $release); if ($rid == $node->version) { - $release = $rid; + $latest_release = $release; break; } // If the version matches the default on the overview, prefer the first. if (!isset($release) && strpos($version, $overview) === 0) { - $release = $rid; + $latest_release = $release; } } // Fallback to the latest - if (!isset($release)) { + if (!isset($latest_release)) { reset($releases); - list($release) = each($releases); + $latest_release = current($releases); } - $release = project_release_load($release); + $release = $latest_release; + $version = theme('project_release_version', $release); // Download section $links = array(); - $links[] = '' . t('Download latest release (%version, %date, %size)', array('%version' => $release->version, '%date' => format_date($release->changed, 'small'), '%size' => format_size(filesize($release->path)))) . ''; + $links[] = '' . t('Download latest release (%version, %date, %size)', array('%version' => $version, '%date' => format_date($release->changed, 'small'), '%size' => format_size(filesize($release->file_path)))) . ''; if ($release->changes) { $links[] = l(t('Read release notes'), 'node/'. $node->nid .'/release', null, null, 'version-'. $release->version); @@ -337,7 +340,7 @@ function project_project_view(&$node, $t } } if (node_access('update', $node) && !variable_get('project_release_directory', '')) { - $links[] = l(t('Add new release'), 'node/'. $node->nid .'/release/add'); + $links[] = l(t('Add new release'), 'node/add/project_release/'. $node->nid); } if ($links) { $output .= theme('item_list', $links, t('Releases')); @@ -402,22 +405,6 @@ function project_project_view(&$node, $t } } -function project_project_releases() { - $node = node_load(arg(1)); - - // Breadcrumb navigation - $breadcrumb[] = array('path' => 'node/'. $node->nid .'/', 'title' => $node->title); - $breadcrumb[] = array('path' => 'node/'. arg(1) .'/release', 'title' => t('Releases')); - $breadcrumb = project_project_set_location($node, $breadcrumb); - - menu_set_location($breadcrumb); - - $output = project_release_list($node); - - drupal_set_title(check_plain($node->title)); - return $output; -} - function project_project_load($node) { $project = db_fetch_object(db_query('SELECT * FROM {project_projects} WHERE nid = %d', $node->nid)); Index: modules/project/project.install =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/project/project.install,v retrieving revision 1.2.2.6 diff -u -F^f -r1.2.2.6 project.install --- modules/project/project.install 10 Sep 2006 06:37:17 -0000 1.2.2.6 +++ modules/project/project.install 10 Sep 2006 19:51:03 -0000 @@ -22,25 +22,7 @@ function project_install() { KEY project_projects_uri (uri(8)) ) TYPE=MyISAM /*!40100 DEFAULT CHARACTER SET utf8 */;"); - db_query("CREATE TABLE {project_releases} ( - rid int(10) unsigned NOT NULL default '0', - nid int(10) unsigned NOT NULL default '0', - fid int(10) unsigned NOT NULL default '0', - path varchar(255) NOT NULL default '', - created int(10) unsigned NOT NULL default '0', - version varchar(255) NOT NULL default '', - status tinyint(1) unsigned NOT NULL default '1', - changes text, - weight tinyint(3) unsigned NOT NULL default '0', - changed int(10) unsigned NOT NULL default '0', - hash varchar(32) NOT NULL default '', - UNIQUE(path), - PRIMARY KEY (`rid`), - KEY project_releases_nid (nid) - ) TYPE=MyISAM - /*!40100 DEFAULT CHARACTER SET utf8 */;"); - break; - + case 'pgsql': db_query("CREATE TABLE {project_projects} ( nid int NOT NULL default '0', @@ -57,20 +39,6 @@ function project_install() { license varchar(255) default '' not null, PRIMARY KEY (nid) );"); - db_query("CREATE TABLE {project_releases} ( - rid int NOT NULL default '0', - nid int NOT NULL default '0', - fid int NOT NULL default '0', - path varchar(255) NOT NULL default '', - created int NOT NULL default '0', - hash varchar(32) NOT NULL default '', - version varchar(255) NOT NULL default '', - changes text, - weight smallint NOT NULL default '0', - changed int NOT NULL default '0', - status smallint default '1' not null, - PRIMARY KEY (rid) - );"); break; } @@ -230,6 +198,60 @@ function project_update_4() { return $ret; } +/** + * Create the {project_release_nodes} table and transfer data into it. + */ +function project_update_5() { + $ret = array(); + + // First, create the new table. + switch ($GLOBALS['db_type']) { + case 'mysql': + case 'mysqli': + $ret[] = update_sql("CREATE TABLE IF NOT EXISTS {project_release_nodes} ( + nid int(10) unsigned NOT NULL default '0', + pid int(10) unsigned NOT NULL default '0', + tag varchar(255) NOT NULL default '0', + file_path varchar(255) NOT NULL default '', + file_date int(10) unsigned NOT NULL default '0', + file_hash varchar(32) NOT NULL default '', + rebuild tinyint(1) default '0', + version_super_major int(10) NOT NULL default 0, + version_super_minor int(10) NOT NULL default 0, + version_major int(10) NOT NULL default 0, + version_minor int(10) NOT NULL default 0, + version_extra varchar(255) NOT NULL default '', + PRIMARY KEY (`nid`), + KEY project_releases_pid (pid) + ) TYPE=MyISAM + /*!40100 DEFAULT CHARACTER SET utf8 */;"); + break; + + case 'pgsql': + if (!project_db_table_exists('project_release_nodes')) { + $ret[] = update_sql("CREATE TABLE {project_release_nodes} ( + nid int NOT NULL default '0', + pid int NOT NULL default '0', + tag varchar(255) NOT NULL default '0', + file_path varchar(255) NOT NULL default '', + file_date int NOT NULL default '0', + file_hash varchar(32) NOT NULL default '', + rebuild smallint default '0', + version_super_major int NOT NULL default 0, + version_super_minor int NOT NULL default 0, + version_major int NOT NULL default 0, + version_minor int NOT NULL default 0, + version_extra varchar(255) NOT NULL default '', + PRIMARY KEY (nid), + KEY project_releases_pid (pid) + );"); + } + break; + } + // TODO: migrate data from old {project_releases} table + // TODO: drop old {project_releases} table +} + function project_db_table_exists($table) { switch ($GLOBALS['db_type']) { case 'mysql': Index: modules/project/project.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/project/project.module,v retrieving revision 1.239.2.13 diff -u -F^f -r1.239.2.13 project.module --- modules/project/project.module 7 Sep 2006 19:25:39 -0000 1.239.2.13 +++ modules/project/project.module 10 Sep 2006 19:51:04 -0000 @@ -1,21 +1,17 @@ project_projects -// project releases -> project_releases - $path = drupal_get_path('module', 'project'); if (file_exists("$path/project.inc")) { require_once "$path/project.inc"; - require_once "$path/release.inc"; } function project_help($section) { switch ($section) { case 'admin/modules#description': - return t('Provides a project node type and manages downloads of project releases.'); + return t('Provides a project node type and browsing of projects.'); case 'node/add#project_project': - return t('A project is anything that has releases which can be downloaded'); + return t('A project is something a group is working on. It can optionally have issue tracking, integration with revision control systems, releases, and so on.' ); case 'node/add/project_project': if (project_use_taxonomy()) { $tree = taxonomy_get_tree(_project_get_vid()); @@ -89,69 +85,27 @@ function project_perm() { * Callback for the main settings page. */ function project_settings() { - $versions = array(-1 => t('all')) + project_releases_list(); $sort_methods = drupal_map_assoc(array_keys(module_invoke_all('project_sort_methods', 'methods'))); - $form['releases'] = array('#type' => 'fieldset', - '#title' => t('Releases'), - '#collapsible' => TRUE, - ); - $form['releases']['project_release_directory'] = array( - '#type' => 'textfield', - '#title' => t('Release directory'), - '#default_value' => variable_get('project_release_directory', ''), - '#size' => 50, - '#maxlength' => 255, - '#description' => t('Leave this blank if project maintainers are to create their own release packages. This is useful if releases are generated by an external tool.'), - ); - - $form['releases']['project_release_unmoderate'] = array( - '#type' => 'radios', - '#title' => t('Unmoderate projects with releases'), - '#default_value' => variable_get('project_release_unmoderate', 0), - '#options' => array('Disabled', 'Enabled'), - ); - - $form['releases']['project_browse_releases'] = array( - '#type' => 'checkbox', - '#title' => t('Browse projects by releases'), - '#default_value' => variable_get('project_browse_releases', 0), - '#description' => t('Checking this box will cause the project browsing page to have a version select.'), - ); - - $form['releases']['project_release_overview'] = array( - '#type' => 'radios', - '#title' => t('Default release overview'), - '#default_value' => variable_get('project_release_overview', -1), - '#options' => $versions, - '#description' => t('Default release version to list on the overview page'), - ); - - $form['browsing'] = array( - '#type' => 'fieldset', - '#title' => t('Browsing options'), - '#collapsible' => TRUE, - ); - if (project_use_taxonomy()) { // For now, date-based browsing doesn't work once you disable // taxonomy (only because the code involved is rather complicated // and needs to be majorly refactored and cleaned up). - $form['browsing']['project_sort_method'] = array( + $form['project_sort_method'] = array( '#type' => 'radios', '#title' => t('Default sort option'), '#default_value' => variable_get('project_sort_method', 'category'), '#options' => $sort_methods, '#description' => t('Default sorting option to use on the overview page'), ); - $form['browsing']['sort_methods'] = array( + $form['sort_methods'] = array( '#type' => 'fieldset', '#title' => t('Enabled sorting options'), ); $tree = taxonomy_get_tree(_project_get_vid(), 0 , -1, 1); foreach ($tree as $term) { - $form['browsing']['sort_methods']['project_sort_method_used_' . $term->tid] = array( + $form['sort_methods']['project_sort_method_used_' . $term->tid] = array( '#type' => 'checkboxes', '#title' => $term->name, '#default_value' => variable_get('project_sort_method_used_' . $term->tid, array_keys($sort_methods)), @@ -160,12 +114,18 @@ function project_settings() { ); } } - $form['browsing']['project_browse_nodes'] = array( + $form['project_browse_nodes'] = array( '#type' => 'select', '#title' => t('Number of projects to list in paged browsing'), '#default_value' => variable_get('project_browse_nodes', 30), '#options' => drupal_map_assoc(array(5, 10, 15, 20, 25, 30, 35, 40, 45, 50)), '#description' => t('The default maximum number of projects to list when browsing lists, e.g., by category.') ); + $form['project_browse_releases'] = array( + '#type' => 'checkbox', + '#title' => t('Browse projects by releases'), + '#default_value' => variable_get('project_browse_releases', 0), + '#description' => t('Checking this box will cause the project browsing page to have a version select.'), + ); if (module_exist('forum') && project_use_taxonomy()) { $form['project_support_forum'] = taxonomy_form(_forum_get_vid(), variable_get('project_support_forum', ''), t('Select the support forum for projects'), 'project_support_forum'); @@ -176,13 +136,6 @@ function project_settings() { return $form; } -function project_cron() { - if (variable_get('project_release_directory', '') && time() - variable_get('project_release_directory_last', 0) > variable_get('project_release_directory_interval', 6 * 60 * 60)) { - variable_set('project_release_directory_last', time()); - project_release_cron(); - } -} - function project_link($type, $node = 0, $main = 0) { $links = array(); switch ($type) { @@ -319,32 +272,9 @@ function project_menu($may_cache) { $access = project_project_access('create', NULL); $items[] = array('path' => 'node/add/project_project', 'title' => t('project'), 'callback' => 'node_page', 'access' => $access, 'type' => MENU_NORMAL_ITEM); - // Releases - if (variable_get('project_release_directory', '')) { - $access = user_access('administer projects'); - $items[] = array('path' => 'admin/settings/project/reload', 'title' => t('scan for releases'), 'callback' => 'project_release_scan', 'access' => $access, 'type' => MENU_NORMAL_ITEM); - } } else { theme_add_style(drupal_get_path('module', 'project') .'/project.css'); - if (arg(0) == 'node' && is_numeric(arg(1))) { - $node = node_load(arg(1)); - if ($node->type == 'project_project') { - $items[] = array('path' => 'node/'. arg(1) .'/release', 'title' => t('releases'), 'callback' => 'project_project_releases', 'access' => node_access('view', $node), 'weight' => 0, 'type' => MENU_CALLBACK); - - if (node_access('update', $node)) { - $items[] = array('path' => 'node/'. arg(1) .'/release/overview', 'title' => t('overview'), 'callback' => 'project_project_releases', 'access' => node_access('view', $node), 'weight' => 0, 'type' => MENU_CALLBACK); - } - - if (!variable_get('project_release_directory', '')) { - $items[] = array('path' => 'node/'. arg(1) .'/release/add', 'title' => t('add'), 'callback' => 'project_release_submit', 'access' => node_access('update', $node), 'weight' => 1, 'type' => MENU_CALLBACK); - } - if (arg(2) == 'release' && is_numeric(arg(4))) { - $items[] = array('path' => 'node/'. arg(1) .'/release/edit/'. arg(4), 'title' => t('edit'), 'callback' => 'project_release_submit', 'access' => node_access('update', $node), 'weight' => 1, 'type' => MENU_CALLBACK); - $items[] = array('path' => 'node/'. arg(1) .'/release/delete/'. arg(4), 'title' => t('edit'), 'callback' => 'project_release_submit', 'access' => node_access('update', $node), 'weight' => 1, 'type' => MENU_CALLBACK); - } - } - } } return $items; @@ -733,9 +663,10 @@ function project_project_sort_methods($o 'order_bys' => array('n.sticky DESC', 'n.title ASC') ); case 'date': + // TODO: this should all be conditional on project_release.module return array( 'fields' => array('MAX(pr.changed) AS changed'), - 'joins' => array('INNER JOIN {project_releases} pr ON n.nid = pr.nid'), + 'joins' => array('INNER JOIN {project_release_nodes} pr ON n.nid = pr.nid'), 'group_bys' => array('n.nid'), 'order_bys' => array('pr.changed DESC', 'n.sticky DESC', 'n.title ASC') ); @@ -779,6 +710,7 @@ function project_project_sort_methods($o return; } +// TODO: refactor for project_release.module? Need {project_release_nodes} function project_default_tid() { static $tid; if ($tid === NULL) { Index: modules/project/project_release.install =================================================================== RCS file: modules/project/project_release.install diff -N modules/project/project_release.install --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/project/project_release.install 10 Sep 2006 19:51:04 -0000 @@ -0,0 +1,62 @@ + array('name' => t('project release'), 'base' => 'project_release'), + ); +} + +function project_release_menu($may_cache) { + $items = array(); + global $user; + + if ($may_cache) { + // Releases + if (variable_get('project_release_directory', '')) { + $access = user_access('administer projects'); + $items[] = array('path' => 'admin/settings/project/reload', 'title' => t('scan for releases'), 'callback' => 'project_release_scan', 'access' => $access, 'type' => MENU_NORMAL_ITEM); + } + } + else { + if (arg(0) == 'node' && is_numeric(arg(1))) { + $node = node_load(arg(1)); + if ($node->type == 'project_project') { + $items[] = array('path' => 'node/'. arg(1) .'/release', 'title' => t('releases'), 'callback' => 'project_release_project_releases', 'access' => node_access('view', $node), 'weight' => 0, 'type' => MENU_CALLBACK); + if (node_access('update', $node)) { + $items[] = array('path' => 'node/'. arg(1) .'/release/overview', 'title' => t('overview'), 'callback' => 'project_release_project_releases', 'access' => node_access('view', $node), 'weight' => 0, 'type' => MENU_CALLBACK); + } + } + } + } + return $items; +} + + +/** + * Callback for the main settings page. + */ +function project_release_settings() { + $versions = array(-1 => t('all')) + project_releases_list(); + $form['project_release_directory'] = array( + '#type' => 'textfield', + '#title' => t('Release directory'), + '#default_value' => variable_get('project_release_directory', ''), + '#size' => 50, + '#maxlength' => 255, + '#description' => t('Leave this blank if project maintainers are to create their own release packages. This is useful if releases are generated by an external tool.'), + ); + + $form['project_release_unmoderate'] = array( + '#type' => 'radios', + '#title' => t('Unmoderate projects with releases'), + '#default_value' => variable_get('project_release_unmoderate', 0), + '#options' => array('Disabled', 'Enabled'), + ); + + $form['project_release_overview'] = array( + '#type' => 'radios', + '#title' => t('Default release overview'), + '#default_value' => variable_get('project_release_overview', -1), + '#options' => $versions, + '#description' => t('Default release version to list on the overview page'), + ); + return $form; +} + +function project_release_cron() { + if (variable_get('project_release_directory', '') && time() - variable_get('project_release_directory_last', 0) > variable_get('project_release_directory_interval', 6 * 60 * 60)) { + variable_set('project_release_directory_last', time()); + // TODO: should be able to optimize this to use less file system calls. + // TODO: commented out until implemented with the new system. + // project_release_scan_directory(); + } +} + + +/** + * -- commented out; needs to be re-implemented using new system, but + * we need to be sure we understand what this is doing, how and why. + +function project_release_scan() { + project_release_scan_directory(); + drupal_set_title(t('Release directory scan')); + foreach (project_release_scan_directory_results() as $type => $count) { + drupal_set_message(t('Releases %type: %count.', array('%type' => $type, '%count' => $count))); + } + return t('Scan completed.'); +} + +function project_release_scan_directory($project = NULL) { + if ($dir = file_create_path(variable_get('project_release_directory', ''))) { + if ($project) { + $regexp = "($project)" .'-(.+)\.(tar.gz|zip)'; + } + else { + $regexp = '(.+)-(.+)\.(tar.gz|zip)'; + } + + file_scan_directory($dir, $regexp, array('.', '..', 'CVS'), 'project_release_scan_parse'); + + // If any releases were previously present but are no longer, unpublish them. + foreach (project_release_scan_parse() as $project) { + if ($project->releases) { + foreach ($project->releases as $rid) { + project_release_delete($rid); + project_release_scan_directory_results(t('unpublished')); + } + } + } + } + project_releases_list(TRUE); +} + +function project_release_scan_directory_results($type = NULL) { + static $results; + if ($type) { + if (!$results[$type]) { + $results[$type] = 1; + } + else { + $results[$type]++; + } + } + return $results; +} + +function project_release_scan_parse($path = NULL) { + static $projects = array(); + + if (is_null($path)) { + return $projects; + } + else { + $dir = dirname($path); + $file = basename($path); + //preg_match('/^(.+?)-([0-9.]+(?:-.*)|[^-]+)\.(tar\.gz|zip)$/', $file, $matches); + preg_match('/^(.+?)-([0-9.]+(?:-.*)|[^-]+)\.(tar.gz$|zip$)/', $file, $matches); + list($filename, $name, $version) = $matches; + + // If the project was not previously loaded, load its data, including previous releases. + if (!$projects[$name]) { + if ($project = db_fetch_object(db_query(db_rewrite_sql("SELECT n.nid, n.type, n.moderate FROM {node} n INNER JOIN {project_projects} p ON n.nid = p.nid WHERE p.uri = '%s'"), $name))) { + if ($releases = project_release_load($project, 0)) { + // Releases are loaded in an array where the key is the rid and the value the version. + // We flip the array to more readily test for releases. + $project->releases = array_flip($releases); + } + // Unmoderate nodes that have gotten releases + if (variable_get('project_release_unmoderate', 0) && $project->moderate) { + db_query("UPDATE {node} SET moderate = 0, status = 1 WHERE nid = %d", $project->nid); + } + } + else { + // No project found for this id. + return; + } + $projects[$name] = & $project; + } + else { + $project = & $projects[$name]; + } + + $release->scan = 1; + $release->nid = $project->nid; + // If the current version was previously released, add its rid value, so that + // it will be updated rather than inserted by project_release_save(); + if (is_array($project->releases) && array_key_exists($version, $project->releases)) { + $release->rid = $project->releases[$version]; + project_release_scan_directory_results(t('updated')); + } + else { + project_release_scan_directory_results(t('created')); + } + $release->version = $version; + $release->path = $path; + project_release_save($release); + // This release version has been resaved, so take it out of the array. + // That way, any releases no longer present can be unpublished in project_release_scan_directory(). + if ($project->releases[$version]) { + unset($project->releases[$version]); + } + } +} +*/ + +/** + * Implementation of hook_form(). + */ +function project_release_form(&$release, &$param) { + if (arg(1) == 'add') { + if (!is_numeric(arg(3))) { + $form['markup'] = array( + '#value' => t('You must add releases only from projects.') + ); + return $form; + } + $release->pid = arg(3); + $project = node_load($release->pid); + if (!$project) { + return drupal_not_found(); + } + $form['project'] = array( + '#type' => 'value', + '#value' => $project, + ); + } + else { + $edit = true; + } + $form['#attributes'] = array("enctype" => "multipart/form-data"); + + $form['title'] = array( + '#type' => 'value', + '#default_value' => $release->title, + ); + + $form['version_major'] = array( + '#type' => 'textfield', + '#title' => t('Major version number'), + '#default_value' => $release->version_major, + '#size' => 20, + '#maxlength' => 10, + '#required' => TRUE, + ); + if ($edit) { + $form['version_major']['#attributes'] = array('disabled' => $edit); + } + + $form['version_minor'] = array( + '#type' => 'textfield', + '#title' => t('Minor version number'), + '#default_value' => $release->version_minor, + '#size' => 20, + '#maxlength' => 10, + '#required' => TRUE, + ); + if ($edit) { + $form['version_minor']['#attributes'] = array('disabled' => $edit); + } + + $form['version_extra'] = array( + '#type' => 'textfield', + '#title' => t('Extra version identifier'), + '#default_value' => $release->version_extra, + '#size' => 20, + '#maxlength' => 10, + '#description' => t('Optionally specify other identifying information for this version, for example "rc1" or "dev". In most cases, this should be left blank.'), + ); + if ($edit) { + $form['version_minor']['#attributes'] = array('disabled' => $edit); + } + + if (!variable_get('project_release_directory', '')) { + $form['file'] = array( + '#type' => 'file', + '#title' => t('File'), + '#size' => 40, + '#description' => ($release->fid) ? + t('A file already exists, if you upload another file the current file will be replaced.') : + 'Choose the file that will be associated with this release.', + ); + } + + $form['body'] = array( + '#type' => 'textarea', + '#title' => t('Changes'), + '#default_value' => $release->body, + '#rows' => 10, + '#cols' => 40, + '#required' => TRUE, + '#description' => t('Enter a description of this version, such as a list of the major changes or updates.'), + ); + $form['format'] = filter_form($node->format); + + $form['pid'] = array( + '#type' => 'value', + '#value' => $release->pid, + ); + $form['tag'] = array( + '#type' => 'value', + '#value' => $release->tag, + ); + $form['rebuild'] = array( + '#type' => 'value', + '#value' => $release->rebuild, + ); + $form['file_hash'] = array( + '#type' => 'value', + '#value' => $release->file_hash, + ); + $form['file_date'] = array( + '#type' => 'value', + '#value' => $release->file_date, + ); + $form['file_path'] = array( + '#type' => 'value', + '#value' => $release->file_path, + ); + $form['version_super_major'] = array( + '#type' => 'value', + '#value' => $release->version_super_major, + ); + $form['version_super_minor'] = array( + '#type' => 'value', + '#value' => $release->version_super_minor, + ); + return $form; +} + +/** + * Implementation of hook_validate(). + */ +function project_release_validate(&$edit, $form) { + $result = db_query("SELECT * FROM {project_release_nodes} WHERE pid = %d AND version_major = %d AND version_minor = %d AND version_extra = '%s' AND version_super_major = %d AND version_super_minor = %d AND nid != %d", $edit->pid, $edit->version_major, $edit->version_minor, $edit->version_extra, $edit->version_super_major, $edit->super_version_minor, $edit->nid); + + if ($release = db_fetch_object($result)) { + form_set_error('version_minor', t('This version already exists for this project.')); + } + + if ($file = file_check_upload('file')) { + $file = file_save_upload('file', file_directory_path()); + if ($file) { + $filepath = file_create_path($file->filepath); + form_set_value($form['file_path'], $file->filepath); + form_set_value($form['file_date'], filemtime($filepath)); + form_set_value($form['file_hash'], md5_file($filepath)); + } + else { + form_set_error('file', t('There was a problem uploading the specified file.')); + } + } + if ($edit->project) { + form_set_value($form['title'], t('%project %version', array('%project' => $edit->project->title, '%version' => theme('project_release_version', (object) $edit)))); + } +} + +/** + * Implementation of hook_load(). + */ +function project_release_load($node) { + $additions = db_fetch_object(db_query("SELECT * FROM {project_release_nodes} WHERE nid = %d", $node->nid)); + return $additions; +} + +/** + * Implementation of hook_insert(). + */ +function project_release_insert($node) { + db_query("INSERT INTO {project_release_nodes} (nid, pid, tag, file_path, file_date, file_hash, rebuild, version_super_major, version_super_minor, version_major, version_minor, version_extra) VALUES (%d, %d, '%s', '%s', %d, '%s', %d, %d, %d, %d, %d, '%s')", $node->nid, $node->pid, $node->tag, $node->file_path, $node->file_date, $node->file_hash, $node->rebuild, $node->version_super_major, $node->version_super_minor, $node->version_major, $node->version_minor, $node->version_extra); +} + +/** + * Implementation of hook_update(). + */ +function project_release_update($node) { + db_query("UPDATE {project_release_nodes} SET pid = %d, tag = '%s', file_path = '%s', file_date = %d, file_hash = '%s', rebuild = %d, version_super_major = %d, version_super_minor = %d, version_major = %d, version_minor = %d, version_extra = '%s' WHERE nid = %d", $node->pid, $node->tag, $node->file_path, $node->file_date, $node->file_hash, $node->rebuild, $node->version_super_major, $node->version_super_minor, $node->version_major, $node->version_minor, $node->version_extra, $node->nid); +} + +/** + * Implementation of hook_delete(). + */ +function project_release_delete($node) { + if ($node->file_path) { + file_delete(file_create_path($node->file_path)); + } + db_query("DELETE FROM {project_release_nodes} WHERE nid = %d", $node->nid); +} + + +/** + * @themeable + * Provide a proper full version name of a file. + */ +function theme_project_release_version($release) { + $version = ''; + if ($release->version_super_major) { + $version .= $release->version_super_major .'.'. $release->version_super_minor .'-'; + } + $version .= $release->version_major .'.'. $release->version_minor; + if ($release->version_extra) { + $version .= '-' . $release->version_extra; + } + return $version; +} + +/** + * Implementation of hook_view(). + */ +function project_release_view(&$release, $teaser = FALSE, $page = FALSE) { + $project = node_load($release->pid); + + if ($page) { + // Breadcrumb navigation + $breadcrumb[] = array('path' => 'node/'. $project->nid, 'title' => $project->title); + $breadcrumb[] = array('path' => 'node/'. $node->nid, 'title' => $node->title); + $breadcrumb = project_project_set_location($project, $breadcrumb); + menu_set_location($breadcrumb); + } + + $links = array(); + if ($release->file_path) { + $output .= '' . t('Download: %file', array('%file' => l(basename($release->file_path), file_create_url($release->file_path)))) . '
'; + $output .= '' . t('Size: %size', array('%size' => format_size(filesize(file_create_path($release->file_path))))) . '
'; + $output .= '' . t('md5_file file_hash: %file_hash', array('%file_hash' => $release->file_hash)) . '
'; + } + if ($release->created) { + $output .= '' . t('First released: %created', array('%created' => format_date($release->created))) . '
'; + } + if ($release->changed && ($release->changed != $release->created)) { + $output .= '' . t('Last updated: %changed', array('%changed' => format_date($release->changed))) . '
'; + } + + $output .= $release->changes; + $output .= theme('links', $links); + + $release->body .= '
' . $output . '
'; +} + +/** + * Display a list of releases for a given project + */ +function project_release_project_releases() { + $node = node_load(arg(1)); + + // Breadcrumb navigation + $breadcrumb[] = array('path' => 'node/'. $node->nid .'/', 'title' => $node->title); + $breadcrumb[] = array('path' => 'node/'. arg(1) .'/release', 'title' => t('Releases')); + $breadcrumb = project_project_set_location($node, $breadcrumb); + + menu_set_location($breadcrumb); + + $output = project_release_list($node); + + drupal_set_title(check_plain($node->title)); + return $output; +} + +/** + * Get an array of release nodes + */ +function project_release_get_releases($project, $nodes = true) { + $result = db_query(db_rewrite_sql("SELECT n.nid, r.* FROM {node} n INNER JOIN {project_release_nodes} r ON r.nid = n.nid WHERE r.pid = %d ORDER BY n.created DESC"), $project->nid); + $releases = array(); + while ($obj = db_fetch_object($result)) { + if ($nodes) { + $releases[$obj->nid] = node_load($obj->nid); + } + else { + $releases[$obj->nid] = theme('project_release_version', $obj); + } + } + return $releases; +} + +function project_release_list($project, $main = 0) { + if ($releases = project_release_get_releases($project)) { + foreach ($releases as $release) { + $output .= node_view($release); + } + return $output; + } +} + +function project_releases_list($refresh = FALSE) { + if (!$refresh && ($versions = cache_get('project_releases'))) { + $versions = unserialize($versions->data); + } + else { + $result = db_query("SELECT version FROM {project_releases} WHERE status = 1 GROUP BY version, created ORDER BY created DESC;"); + $versions = array(); + while ($object = db_fetch_object($result)) { + $version = preg_replace('/^(.+?)\.?(?:\d+)?$/', '\1', $object->version); + $versions[$version] = $version == $object->version ? $version : $version .'.x'; + } + cache_set('project_releases', serialize($versions)); + menu_rebuild(); + } + + return $versions; +} Index: modules/project/release.inc =================================================================== RCS file: modules/project/release.inc diff -N modules/project/release.inc --- modules/project/release.inc 4 Aug 2006 03:19:50 -0000 1.70.2.3 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,437 +0,0 @@ - $count) { - drupal_set_message(t('Releases %type: %count.', array('%type' => $type, '%count' => $count))); - } - return t('Scan completed.'); -} - -function project_release_scan_directory($project = NULL) { - if ($dir = file_create_path(variable_get('project_release_directory', ''))) { - if ($project) { - $regexp = "($project)" .'-(.+)\.(tar.gz|zip)'; - } - else { - $regexp = '(.+)-(.+)\.(tar.gz|zip)'; - } - - file_scan_directory($dir, $regexp, array('.', '..', 'CVS'), 'project_release_scan_parse'); - - // If any releases were previously present but are no longer, unpublish them. - foreach (project_release_scan_parse() as $project) { - if ($project->releases) { - foreach ($project->releases as $rid) { - project_release_delete($rid); - project_release_scan_directory_results(t('unpublished')); - } - } - } - } - project_releases_list(TRUE); -} - -function project_release_scan_directory_results($type = NULL) { - static $results; - if ($type) { - if (!$results[$type]) { - $results[$type] = 1; - } - else { - $results[$type]++; - } - } - return $results; -} - -function project_release_scan_parse($path = NULL) { - static $projects = array(); - - if (is_null($path)) { - return $projects; - } - else { - $dir = dirname($path); - $file = basename($path); - //preg_match('/^(.+?)-([0-9.]+(?:-.*)|[^-]+)\.(tar\.gz|zip)$/', $file, $matches); - preg_match('/^(.+?)-([0-9.]+(?:-.*)|[^-]+)\.(tar.gz$|zip$)/', $file, $matches); - list($filename, $name, $version) = $matches; - - // If the project was not previously loaded, load its data, including previous releases. - if (!$projects[$name]) { - if ($project = db_fetch_object(db_query(db_rewrite_sql("SELECT n.nid, n.type, n.moderate FROM {node} n INNER JOIN {project_projects} p ON n.nid = p.nid WHERE p.uri = '%s'"), $name))) { - if ($releases = project_release_load($project, 0)) { - // Releases are loaded in an array where the key is the rid and the value the version. - // We flip the array to more readily test for releases. - $project->releases = array_flip($releases); - } - // Unmoderate nodes that have gotten releases - if (variable_get('project_release_unmoderate', 0) && $project->moderate) { - db_query("UPDATE {node} SET moderate = 0, status = 1 WHERE nid = %d", $project->nid); - } - } - else { - // No project found for this id. - return; - } - $projects[$name] = & $project; - } - else { - $project = & $projects[$name]; - } - - $release->scan = 1; - $release->nid = $project->nid; - // If the current version was previously released, add its rid value, so that - // it will be updated rather than inserted by project_release_save(); - if (is_array($project->releases) && array_key_exists($version, $project->releases)) { - $release->rid = $project->releases[$version]; - project_release_scan_directory_results(t('updated')); - } - else { - project_release_scan_directory_results(t('created')); - } - $release->version = $version; - $release->path = $path; - project_release_save($release); - // This release version has been resaved, so take it out of the array. - // That way, any releases no longer present can be unpublished in project_release_scan_directory(). - if ($project->releases[$version]) { - unset($project->releases[$version]); - } - } -} - -function project_release_cron() { - // TODO: should be able to optimize this to use less file system calls. - if ($dir = variable_get('project_release_directory', '')) { - project_release_scan_directory(); - } -} - -function project_release_submit() { - switch ($_POST['op'] ? $_POST['op'] : arg(3)) { - case 'add': - $node = node_load(arg(1)); - $breadcrumb = array(l(t('Home'), NULL), l(t('Projects'), 'project')); - if (project_use_taxonomy()) { - $taxonomy_terms = taxonomy_node_get_terms($node->nid); - $term = reset($taxonomy_terms); - $breadcrumb[] = l($term->name, 'project', NULL, "tid=$term->tid"); - } - $breadcrumb[] = l($node->title, "node/$node->nid"); - $error = 1; - $release->nid = $node->nid; - $form = project_release_form($release, $param); - $output = drupal_get_form('project_release_form', $form); - - drupal_set_title(t('Add release to %project', array('%project' => $node->title))); - drupal_set_breadcrumb($breadcrumb); - return $output; - break; - case 'edit': - if ($release = project_release_load(arg(4))) { - $node = node_load($release->nid); - $output = project_release_view($release); - $form = project_release_form($release, $param); - $output = drupal_get_form('project_release_form', $form); - drupal_set_title(t('Edit release %version for %project', array('%version' => $release->version, '%project' => $node->title))); - return $output; - } - break; - case 'delete': - if (($release = project_release_load(arg(4))) && $release->nid == arg(1)) { - project_release_delete(arg(4)); - drupal_goto("node/$release->nid/release"); - } - break; - case t('Submit'): - $edit = (object) $_POST['edit']; - $node = node_load($edit->nid); - if (node_access('update', $node)) { - project_release_validate($edit); - if (form_get_errors()) { - $form = project_release_form($release, $param); - $output = drupal_get_form('project_release_form', $form); - return $output; - } - else { - // Save the release and re-direct to the overview page for the project - $edit->status = 1; - project_release_save($edit); - drupal_goto("node/$node->nid/release"); - } - } - } -} - -/** - * Implementation of hook_form(). - */ -function project_release_form(&$release, &$param) { - /* TODO: pending final fileapi - // Set form parameters so we can accept file uploads. - $param['options'] = array('enctype' => 'multipart/form-data'); - */ - - $form['version'] = array( - '#type' => 'textfield', - '#title' => t('Version'), - '#default_value' => $release->version, - '#size' => 40, - '#maxlength' => 255, - '#required' => TRUE, - ); - $form['changes'] = array( - '#type' => 'textarea', - '#title' => t('Changes'), - '#default_value' => $release->changes, - '#rows' => 10, - '#cols' => 40, - '#required' => TRUE, - ); - if (!variable_get('project_release_directory', '')) { - $form['path'] = array( - '#type' => 'file', - '#title' => t('File'), - '#size' => 40, - '#description' => ($release->fid) ? - t('A file already exists, if you upload another file the current file will be replaced.') : - '' . $error['file'], - '#required' => $release->fid, - ); - } - if ($release->rid) { - $form['rid'] = array( - '#type' => 'hidden', - '#default_value' => $release->rid, - ); - } - $form['nid'] = array( - '#type' => 'hidden', - '#default_value' => $release->nid, - ); - - if (!form_get_errors()) { - $form['submit'] = array( - '#type' => 'button', - '#value' => t('Submit'), - ); - } - - return $form; -} - -function project_release_validate(&$edit) { - if ($edit->rid) { - $release = project_release_load($edit->rid); - $edit->nid = $release->nid; - $edit->fid = $release->fid; - } - - if (empty($edit->version)) { - form_set_error('version', t('You must specify a valid version.')); - } - else { - $result = db_query("SELECT * FROM {project_releases} WHERE nid = %d AND version = '%s'", $edit->nid, trim($edit->version)); - if ($release = db_fetch_object($result)) { - if ($edit->rid != $release->rid) { - if ($release->status) { - form_set_error('version', t('This version already exists for this project.')); - } - else { - $edit->rid = $release->rid; - } - } - } - } - - if (empty($edit->changes)) { - form_set_error('changes', t('You must specify changes.')); - } - - /* TODO: pending final fileapi - $file = check_file('file'); - - if ($file && !$file->fid && !empty($file->error)) { - $error['file'] = theme('error', $file->error); - } - else { - $edit->fid = $file->fid; - } - */ -} - -function project_release_view($release, $project = 0) { - if (!$project) { - $project = node_load($release->nid); - } - - $links = array(); - if ($release->rid && node_access('update', $project)) { - $links[] = l('edit', "node/$project->nid/release/edit/$release->rid"); - //$links[] = l('delete', "node/$project->nid/release/delete/$release->rid"); - } - - if ($release->path) { - $output .= '' . t('Download: %path', array('%path' => base_path() . $release->path)) . '
'; - $output .= '' . t('Size: %size', array('%size' => format_size(filesize($release->path)))) . '
'; - $output .= '' . t('md5_file hash: %hash', array('%hash' => $release->hash)) . '
'; - } - if ($release->created) { - $output .= '' . t('First released: %created', array('%created' => format_date($release->created))) . '
'; - } - if ($release->changed && ($release->changed != $release->created)) { - $output .= '' . t('Last updated: %changed', array('%changed' => format_date($release->changed))) . '
'; - } - - $output .= $release->changes; - $output .= theme('links', $links); - - return $output; -} - -function project_release_list($project, $main = 0) { - $result = db_query('SELECT * FROM {project_releases} WHERE nid = %d AND status = 1 ORDER BY created DESC', $project->nid); - if (db_num_rows($result)) { - $header = array(t('Version'), t('Released'), t('Changes')); - if (node_access('update', $project) || node_access('delete', $project)) { - $header[] = array('data' => t('Operations'), 'colspan' => 2); - } - while ($release = db_fetch_object($result)) { - $output .= theme('box', l(t('%project %version', array('%project' => $project->title, '%version' => $release->version)), 'node/'. $project->nid .'/release', array('id' => 'version-'. $release->version), NULL, 'version-'. $release->version), project_release_view($release, $project)); - } - return $output; - } -} - -function project_release_load($rid, $status = 1) { - if ($rid->type == 'project_project') { - $status = $status ? 'AND status = 1' : ''; - $result = db_query("SELECT rid,version FROM {project_releases} WHERE nid = %d $status ORDER BY version DESC", $rid->nid); - $releases = array(); - while ($release = db_fetch_object($result)) { - $releases[$release->rid] = $release->version; - } - return $releases; - } - elseif (is_numeric($rid)) { - return db_fetch_object(db_query('SELECT * FROM {project_releases} WHERE rid = %d ORDER BY created DESC', $rid)); - } -} - -function project_release_save($release) { - $fields = array('rid' => '%d', 'nid' => '%d', 'fid' => '%d', - 'path' => "'%s'", 'created' => '%d', - 'changed' => '%d', 'hash' => "'%s'", 'version' => "'%s'", - 'changes' => "'%s'", 'status' => '%d'); - - $node = node_load($release->nid); - - /* TODO: pending final fileapi - $file = check_file('file'); - */ - // If the version was not previously released, insert it. - if (empty($release->rid)) { - - // Make sure this release version doesn't already exist for the given project. - // This test should not be needed, but duplicate releases on drupal.org suggest - // that an unidentified problem is causing duplicate versions to be saved. - if (db_num_rows(db_fetch_object(db_query("SELECT rid FROM {project_releases} WHERE nid = %d AND version = '%s'", $release->nid, $release->version)))) { - return FALSE; - } - $release->rid = db_next_id('project_rid'); - if (!variable_get('project_release_directory', '') && $file->filename) { - $release->fid = drupal_file_save($file); - } - if ($release->path) { - $release->created = ($release->version == 'cvs') ? 0 : filectime($release->path); - $release->changed = filemtime($release->path); - $release->hash = md5_file($release->path); - } - else { - $release->created = ($release->version == 'cvs') ? 0 : time(); - $release->changed = time(); - } - - // Prepare the query: - foreach ($release as $key => $value) { - if (in_array($key, array_keys($fields))) { - $input[db_escape_string($key)] = $fields[$key]; - $values[] = $value; - } - } - - // Insert the node into the database: - db_query('INSERT INTO {project_releases} ('. implode(', ', array_keys($input)) .') VALUES('. implode(', ', $input) .')', $values); - watchdog('project', t("added release %version to %project.", array('%version' => theme('placeholder', $release->version), '%project' => theme('placeholder', $node->title)))); - } - // Otherwise, update the existing record. - else { - /* TODO: pending final fileapi - // Replace current file if new file upload exists. - if (!variable_get('project_release_directory', '') && $file->filename) { - $file->fid = $release->fid; - drupal_file_save($file); - } - */ - - unset($release->created); - if($release->path) { - if ($release->scan) { - // Load previous md5_file hash value, and test it agains the current one to see if the file has changed. - $previous = db_fetch_object(db_query("SELECT hash FROM {project_releases} WHERE rid = %d", $release->rid)); - if (md5_file($release->path) != $previous->hash) { - $release->hash = md5_file($release->path); - $release->changed = time(); - } - } - else { - $release->hash = md5_file($release->path); - $release->changed = filemtime($release->path); - } - } - - // Prepare the query: - foreach ($release as $key => $value) { - - if (in_array($key, array_keys($fields))) { - $q[] = db_escape_string($key) ." = " . $fields[$key]; - $v[] = $value; - } - } - $v[] = $release->nid; - $v[] = $release->rid; - - db_query('UPDATE {project_releases} SET '. implode(', ', $q) .' WHERE nid = %d AND rid = %d', $v); - watchdog('project', t("updated release %project %version", array('%project' => theme('placeholder', $node->title), '%version' => theme('placeholder', $release->version)))); - } - return $release->rid; -} - -function project_release_delete($rid) { - $release = project_release_load($rid); - watchdog('project', t("unpublished release %version", array('%version' => theme('placeholder', $release->version)))); - db_query('UPDATE {project_releases} SET status = 0 WHERE rid = %d', $rid); -} - -function project_releases_list($refresh = FALSE) { - if (!$refresh && ($versions = cache_get('project_releases'))) { - $versions = unserialize($versions->data); - } - else { - $result = db_query("SELECT version FROM {project_releases} WHERE status = 1 GROUP BY version, created ORDER BY created DESC;"); - $versions = array(); - while ($object = db_fetch_object($result)) { - $version = preg_replace('/^(.+?)\.?(?:\d+)?$/', '\1', $object->version); - $versions[$version] = $version == $object->version ? $version : $version .'.x'; - } - cache_set('project_releases', serialize($versions)); - menu_rebuild(); - } - - return $versions; -} cvs diff: Diffing modules/project/po cvs diff: Diffing modules/project/po/ar