* Copyright 2003-2010, Roland Mas, Franck Villaume
* Copyright 2004, GForge, LLC
* Copyright 2010, Alain Peyrat <aljeux@free.fr>
- * Copyright 2012-2014,2016-2017, Franck Villaume - TrivialDev
+ * Copyright 2012-2014,2016-2018,2021-2022, Franck Villaume - TrivialDev
* Copyright 2013, French Ministry of National Education
*
* This file is part of FusionForge.
require_once $gfcommon.'include/plugins_utils.php';
-forge_define_config_item('default_server', 'scmsvn', forge_get_config ('scm_host'));
+forge_define_config_item('default_server', 'scmsvn', forge_get_config('scm_host'));
forge_define_config_item('repos_path', 'scmsvn', forge_get_config('chroot').'/scmrepos/svn');
forge_define_config_item('serve_path', 'scmsvn', forge_get_config('repos_path'));
-forge_define_config_item('use_ssh', 'scmsvn', false);
-forge_set_config_item_bool('use_ssh', 'scmsvn');
-forge_define_config_item('use_dav', 'scmsvn', true);
-forge_set_config_item_bool('use_dav', 'scmsvn');
-forge_define_config_item('use_ssl', 'scmsvn', true);
-forge_set_config_item_bool('use_ssl', 'scmsvn');
-forge_define_config_item('anonsvn_login','scmsvn', 'anonsvn');
-forge_define_config_item('anonsvn_password','scmsvn', 'anonsvn');
+forge_define_config_item_bool('use_ssh', 'scmsvn', false);
+forge_define_config_item_bool('use_dav', 'scmsvn', true);
+forge_define_config_item_bool('use_ssl', 'scmsvn', true);
forge_define_config_item('ssh_port', 'core', 22);
class SVNPlugin extends SCMPlugin {
+
+ var $svn_root_dav;
+ var $svn_root_fs;
+ var $web_port;
+
function __construct() {
parent::__construct();
$this->name = 'scmsvn';
_("This plugin contains the Subversion subsystem of FusionForge. It allows
each FusionForge project to have its own Subversion repository, and gives
some control over it to the project's administrator.");
- $this->svn_root_fs = forge_get_config('repos_path',
- $this->name);
+ $this->svn_root_fs = forge_get_config('repos_path', $this->name);
$this->svn_root_dav = '/svn';
+ $this->_addHook('scm_admin_form');
$this->_addHook('scm_browser_page');
$this->_addHook('scm_update_repolist');
$this->_addHook('scm_regen_apache_auth');
$this->_addHook('scm_generate_snapshots');
$this->_addHook('scm_gather_stats');
+ $this->_addHook('scm_admin_form');
+ $this->_addHook('scm_add_repo');
+ $this->_addHook('scm_delete_repo');
$this->_addHook('get_scm_repo_list');
$this->_addHook('get_scm_repo_info');
$this->_addHook('parse_scm_repo_activities');
$this->_addHook('activity');
$this->provides['svn'] = true;
-
+ $this->web_port = util_url_port(forge_get_config('use_ssl', 'scmsvn'));
$this->register();
}
return;
}
- if ($project->usesPlugin($this->name) && forge_check_perm('scm', $project->getID(), 'read')) {
+ if (forge_check_perm('scm', $project->getID(), 'read')) {
$result = db_query_params('SELECT sum(updates) AS updates, sum(adds) AS adds FROM stats_cvs_group WHERE group_id=$1',
array($project->getID()));
$commit_num = db_result($result,0,'updates');
. '</p>';
}
- function topModule($project) {
- // Check toplevel module presence
- $repo = 'file://' . forge_get_config('repos_path', $this->name).'/'.$project->getUnixName().'/';
- $res = array ();
- $module = 'trunk';
- if (!(exec("svn ls '$repo'", $res) && in_array($module.'/', $res))) {
- $module = '';
+ function topModule($project, $repo_name) {
+ $scm_paths = array();
+ $scm_paths_file = forge_get_config('groupdir_prefix').'/'.$project->getUnixName().'/'.$repo_name.'_scmsvn_paths.txt';
+ if (file_exists($scm_paths_file)) {
+ $scm_paths = array_map("htmlentities", file($scm_paths_file));
}
-
- return '/'.$module;
+ // Check scm_path module presence in repository
+ $modules = array();
+ $repo = 'file://' . forge_get_config('repos_path', $this->name).'/'.$repo_name;
+ foreach ($scm_paths as $scm_path) {
+ $scm_path = trim($scm_path);
+ if (strpos($scm_path, "!") === false) {
+ $res = array();
+ exec("svn info '$repo'", $res);
+ if (!preg_grep("/svn: warning: W170000: URL/", $res)) {
+ if (substr($scm_path, 0, 1) === '/') {
+ $modules[] = $scm_path;
+ } else {
+ $modules[] = '/'.$scm_path;
+ }
+ }
+ }
+ }
+ if (empty($modules)) {
+ $modules[] = '/';
+ }
+ return $modules;
}
function getInstructionsForAnon($project) {
- $b = '<h2>' . _('Anonymous Subversion Access') . '</h2>';
- $b .= '<p>';
- $b .= _("This project's SVN repository can be checked out through anonymous access with the following command(s).");
- $b .= '</p>';
+ $repo_list = array($project->getUnixName());
+ $result = db_query_params('SELECT repo_name FROM scm_secondary_repos WHERE group_id=$1 AND next_action = $2 AND plugin_id=$3 ORDER BY repo_name',
+ array($project->getID(), SCM_EXTRA_REPO_ACTION_UPDATE, $this->getID()));
+ $rows = db_numrows($result);
+
+ for ($i = 0; $i < $rows; $i++) {
+ $repo_list[] = db_result($result, $i, 'repo_name');
+ }
+
+ $b = html_e('h2', array(), _('Anonymous Access'));
+ $b .= html_e('p', array(),
+ ngettext("This project's SVN repository can be checked out through anonymous access with the following command(s).",
+ "This project's SVN repositories can be checked out through anonymous access with the following command(s).",
+ count($repo_list)));
- $b .= '<p>' ;
- $module = $this->topModule($project);
if (forge_get_config('use_ssh', 'scmsvn')) {
$ssh_port = '';
if (forge_get_config('ssh_port') != 22) {
$ssh_port = '--config-option="config:tunnels:ssh=ssh -p '.forge_get_config('ssh_port').'"';
}
- $b .= '<span class="tt">svn '.$ssh_port.' checkout svn://'.forge_get_config('scm_host').$this->svn_root_fs.'/'.$project->getUnixName().$module.'</span><br />';
+ $b .= html_e('h3', array(), _('via SVN'));
+ foreach ($repo_list as $repo_name) {
+ $modules = $this->topModule($project, $repo_name);
+ foreach ($modules as $module) {
+ $b .= html_e('kbd', array(), 'svn '.$ssh_port.' checkout svn://'.$this->getBoxForProject($project).$this->svn_root_fs.'/'.$repo_name.$module).html_e('br');
+ }
+ }
}
+
if (forge_get_config('use_dav', 'scmsvn')) {
- $b .= '<p><span class="tt">svn checkout http'.((forge_get_config('use_ssl', 'scmsvn')) ? 's' : '').'://'. forge_get_config('scm_host'). '/anonscm/svn/'.$project->getUnixName().$module.'</span></p>' ;
+ $b .= html_e('h3', array(), _('via DAV'));
+ foreach ($repo_list as $repo_name) {
+ $modules = $this->topModule($project, $repo_name);
+ foreach ($modules as $module) {
+ $b .= html_e('kbd', array(), 'svn checkout http'.((forge_get_config('use_ssl', 'scmsvn')) ? 's' : '').'://'. $this->getBoxForProject($project).$this->web_port.'/anonscm/svn/'.$repo_name.$module).html_e('br');
+ }
+ }
}
- $b .= '</p>';
return $b;
}
function getInstructionsForRW($project) {
- $b = '';
+ $repo_list = array($project->getUnixName());
+ $result = db_query_params('SELECT repo_name FROM scm_secondary_repos WHERE group_id=$1 AND next_action = $2 AND plugin_id=$3 ORDER BY repo_name',
+ array($project->getID(), SCM_EXTRA_REPO_ACTION_UPDATE, $this->getID()));
+ $rows = db_numrows($result);
+ for ($i=0; $i<$rows; $i++) {
+ $repo_list[] = db_result($result, $i, 'repo_name');
+ }
- $module = $this->topModule($project);
- $b .= html_e('h2', array(), _('Developer Access'));
+ $b = html_e('h2', array(), _('Developer Access'));
$b .= sprintf(_('Only project developers can access the %s tree via this method.'), 'Subversion');
$b .= '<div id="tabber-svn">';
$b .= '<ul>';
$b .= _('SSH must be installed on your client machine.');
$b .= ' ';
$b .= _('Enter your site password when prompted.');
- $b .= '</p>';
+ $b .= '</p><p>';
$ssh_port = '';
if (forge_get_config('ssh_port') != 22) {
$ssh_port = '--config-option="config:tunnels:ssh=ssh -p '.forge_get_config('ssh_port').'" ';
}
- $b .= '<p><span class="tt">svn '.$ssh_port.'checkout svn+ssh://'.$d.'@' . forge_get_config('scm_host') . $this->svn_root_fs .'/'. $project->getUnixName().$module.'</span></p>' ;
- $b .= '</div>';
+ foreach ($repo_list as $repo_name) {
+ $modules = $this->topModule($project, $repo_name);
+ foreach ($modules as $module) {
+ if (forge_get_config('use_shell_limited')) {
+ $b .= html_e('kbd', array(), 'svn '.$ssh_port.'checkout svn+ssh://'.$d.'@'.$this->getBoxForProject($project).'/'.$repo_name.$module).html_e('br');
+ } else {
+ $b .= html_e('kbd', array(), 'svn '.$ssh_port.'checkout svn+ssh://'.$d.'@'.$this->getBoxForProject($project).$this->svn_root_fs.'/'.$repo_name.$module).html_e('br');
+ }
+ }
+ }
+ $b .= '</p></div>';
}
if (forge_get_config('use_dav', 'scmsvn')) {
$b .= '<div id="tabber-svndav" class="tabbertab" >';
$b .= '<p>';
$b .= _('Enter your site password when prompted.');
$b .= '</p>';
- $b .= '<p><span class="tt">svn checkout --username '.$d.' http'.((forge_get_config('use_ssl', 'scmsvn')) ? 's' : '').'://'. forge_get_config('scm_host'). '/authscm/'.$d.'/svn/'.$project->getUnixName().$module.'</span></p>' ;
+ foreach ($repo_list as $repo_name) {
+ $modules = $this->topModule($project, $repo_name);
+ foreach ($modules as $module) {
+ $b .= html_e('kbd', array(), 'svn checkout --username '.$d.' http'.((forge_get_config('use_ssl', 'scmsvn')) ? 's' : '').'://'.$this->getBoxForProject($project).$this->web_port.'/authscm/'.$d.'/svn/'.$repo_name.$module).html_e('br');
+ }
+ }
$b .= '</div>';
}
} else {
if (forge_get_config('use_ssh', 'scmsvn')) {
$b .= '<div id="tabber-svnssh" class="tabbertab" >';
- $b .= '<p>';
- $b .= _('SSH must be installed on your client machine.');
- $b .= ' ';
- $b .= _('Substitute <em>developername</em> with the proper value.');
- $b .= ' ';
- $b .= _('Enter your site password when prompted.');
- $b .= '</p>';
+ $b .= html_e('p', array(),
+ ngettext('Only project developers can access the SVN repository via this method.',
+ 'Only project developers can access the SVN repositories via this method.',
+ count($repo_list)).
+ ' '. _('SSH must be installed on your client machine.').
+ ' '. _('Additionally, a public ssh key must be available in the FusionForge settings of the respective user.').
+ ' '. _('Substitute <em>developername</em> with the proper value.')).'<p>';
$ssh_port = '';
if (forge_get_config('ssh_port') != 22) {
$ssh_port = '--config-option="config:tunnels:ssh=ssh -p '.forge_get_config('ssh_port').'" ';
}
- $b .= '<p><span class="tt">svn '.$ssh_port.'checkout svn+ssh://<i>'._('developername').'</i>@' . forge_get_config('scm_host') . $this->svn_root_fs .'/'. $project->getUnixName().$module.'</span></p>' ; $b .= '</div>';
+ foreach ($repo_list as $repo_name) {
+ $modules = $this->topModule($project, $repo_name);
+ foreach ($modules as $module) {
+ if (forge_get_config('use_shell_limited')) {
+ $b .= html_e('kbd', array(), 'svn '.$ssh_port.'checkout svn+ssh://'.html_e('em', array(), _('developername'), true, false).'@'.$this->getBoxForProject($project).'/'.$repo_name.$module).html_e('br');
+ } else {
+ $b .= html_e('kbd', array(), 'svn '.$ssh_port.'checkout svn+ssh://'.html_e('em', array(), _('developername'), true, false).'@'.$this->getBoxForProject($project).$this->svn_root_fs .'/'.$repo_name.$module).html_e('br');
+ }
+ }
+ }
+ $b .= '</p></div>';
}
if (forge_get_config('use_dav', 'scmsvn')) {
$b .= '<div id="tabber-svndav" class="tabbertab" >';
$b .= ' ';
$b .= _('Enter your site password when prompted.');
$b .= '</p>';
- $b .= '<p><span class="tt">svn checkout --username <i>'._('developername').'</i> http'.((forge_get_config('use_ssl', 'scmsvn')) ? 's' : '').'://'. forge_get_config('scm_host'). '/authscm/<i>'._('developername').'</i>/svn/'.$project->getUnixName().$module.'</span></p>' ;
+ foreach ($repo_list as $repo_name) {
+ $modules = $this->topModule($project, $repo_name);
+ foreach ($modules as $module) {
+ $b .= html_e('kbd', array(), 'svn checkout --username '.html_e('em', array(), _('developername'),true, false).' http'.((forge_get_config('use_ssl', 'scmsvn')) ? 's' : '').'://'.$this->getBoxForProject($project).$this->web_port.'/authscm/'.html_e('em', array(), _('developername'),true, false).'/svn/'.$repo_name.$module).html_e('br');
+ }
+ }
$b .= '</div>';
}
}
}
function getSnapshotPara($project) {
- return ;
+ $b = '';
+ $filename = $project->getUnixName().'-scm-latest.tar'.util_get_compressed_file_extension();
+ if (file_exists(forge_get_config('scm_snapshots_path').'/'.$filename)) {
+ $b .= html_e('p', array(), '['.util_make_link("/snapshots.php?group_id=".$project->getID(), _('Download the nightly snapshot')).']');
+ }
+ return $b;
}
function getBrowserLinkBlock($project) {
$b = html_e('h2', array(), _('Subversion Repository Browser'));
- $b .= '<p>';
- $b .= sprintf(_("Browsing the %s tree gives you a view into the current status of this project's code."), 'Subversion');
- $b .= ' ';
- $b .= _('You may also view the complete histories of any file in the repository.');
- $b .= '</p>';
- $b .= '<p>[' ;
- $b .= util_make_link ("/scm/browser.php?group_id=".$project->getID(),
- sprintf(_('Browse %s Repository'), 'Subversion')
- ) ;
- $b .= ']</p>' ;
+ $b .= html_e('p', array(),_("Browsing the Subversion tree gives you a view into the current status of this project's code.")
+ .' '
+ ._('You may also view the complete histories of any file in the repository.'));
+ $b .= html_e('p', array(), '['.util_make_link ("/scm/browser.php?group_id=".$project->getID().'&scm_plugin='.$this->name, sprintf(_('Browse %s Repository'), 'Subversion')).']');
+ # Extra repos
+ $repo_list = $this->getRepositories($project, false);
+ foreach ($repo_list as $repo_name) {
+ $b .= '['.util_make_link('/scm/browser.php?group_id='.$project->getID().'&extra='.$repo_name.'&scm_plugin='.$this->name, _('Browse extra SVN repository')._(': ').$repo_name).']'.html_e('br');
+ }
return $b ;
}
_('Adds'),
_('Updates')
);
- $b .= $HTML->listTableTop($tableHeaders, array(), '', 'repo-history');
+ $b .= $HTML->listTableTop($tableHeaders, array(), '', 'repo-history-'.$this->name);
$i = 0;
$total = array('adds' => 0, 'updates' => 0);
$b .= $HTML->multiTableRow(array(), $cells);
$b .= $HTML->listTableBottom();
} else {
- $b .= $HTML->information(_('No history yet'));
+ $b .= $HTML->warning_msg(_('No history yet.'));
}
return $b;
}
function printBrowserPage($params) {
- global $HTML;
- $useautoheight = 0;
+ if ($params['scm_plugin'] != $this->name) {
+ return;
+ }
$project = $this->checkParams($params);
if (!$project) {
return;
}
-
- if ($project->usesPlugin($this->name)) {
+ if (isset($params['extra']) && !empty($params['extra']) && $params['extra'] != 'none') {
+ $iframe_src = '/scm/viewvc.php?root='.$params['extra'];
+ } else {
$iframe_src = '/scm/viewvc.php?root='.$project->getUnixName();
- if ($params['commit']) {
- $iframe_src .= '&view=rev&revision='.$params['commit'];
- }
- htmlIframe($iframe_src, array('id'=>'scmsvn_iframe'));
}
+ if ($params['commit']) {
+ $iframe_src .= '&view=rev&revision='.$params['commit'];
+ }
+ htmlIframe($iframe_src, array('id'=>'scmsvn_iframe'));
}
function createOrUpdateRepo($params) {
$project = $this->checkParams($params);
- if (!$project) return false;
- if (!$project->isActive()) return false;
- if (!$project->usesPlugin($this->name)) return false;
-
+ if (!$project) {
+ return false;
+ }
$repo_prefix = forge_get_config('repos_path', 'scmsvn');
if (!is_dir($repo_prefix) && !mkdir($repo_prefix, 0755, true)) {
return false;
}
- $repo = $repo_prefix . '/' . $project->getUnixName();
+ $repo = $repo_prefix.'/'.$project->getUnixName();
if (!is_dir ($repo) || !is_file ("$repo/format")) {
if (!mkdir($repo, 0700, true)) {
} else {
system("chmod g+rX-w,o-rwx $repo") ;
}
+
+ // Create project-wide secondary repositories
+ $result = db_query_params('SELECT repo_name FROM scm_secondary_repos WHERE group_id = $1 AND next_action = $2 AND plugin_id = $3',
+ array($project->getID(),
+ SCM_EXTRA_REPO_ACTION_UPDATE,
+ $this->getID()));
+ $rows = db_numrows($result);
+ for ($i = 0; $i < $rows; $i++) {
+ $repo_name = db_result($result, $i, 'repo_name');
+ $repo = $repo_prefix.'/'.$repo_name;
+ if (!is_dir($repo) || !is_file("$repo/format")) {
+ if (!mkdir($repo, 0700, true)) {
+ return false;
+ }
+ $ret = 0;
+ system ("svnadmin create $repo", $ret);
+ if ($ret != 0) {
+ return false;
+ }
+ system ("sed -i '/enable-rep-sharing = false/s/^. //' $repo/db/fsfs.conf") ;
+ // dav/ directory is required by old svn clients (eg. svn 1.6.17 on ubuntu 12.04)
+ if (!is_dir ("$repo/dav")) {
+ mkdir("$repo/dav");
+ }
+ system ("svn mkdir -m'Init' file:///$repo/trunk file:///$repo/tags file:///$repo/branches >/dev/null") ;
+ system ("find $repo -type d -print0 | xargs -r -0 chmod g+s") ;
+ // Allow read/write users to modify the SVN repository
+ $rw_unix_group = $project->getUnixName() . '_scmrw';
+ system("chgrp -R $rw_unix_group $repo");
+ // Allow read-only users to enter the (top-level) directory
+ $ro_unix_group = $project->getUnixName() . '_scmro';
+ system("chgrp $ro_unix_group $repo");
+ // open permissions to allow switching private/public easily
+ // see after to restrict the top-level directory
+ system ("chmod -R g+rwX,o+rX-w $repo") ;
+ }
+ if ($project->enableAnonSCM()) {
+ system("chmod g+rX-w,o+rX-w $repo") ;
+ } else {
+ system("chmod g+rX-w,o-rwx $repo") ;
+ }
+ }
+
+ // Delete project-wide secondary repositories
+ $result = db_query_params('SELECT repo_name FROM scm_secondary_repos WHERE group_id=$1 AND next_action = $2 AND plugin_id=$3',
+ array($project->getID(),
+ SCM_EXTRA_REPO_ACTION_DELETE,
+ $this->getID()));
+ $rows = db_numrows ($result);
+ for ($i=0; $i<$rows; $i++) {
+ $repo_name = db_result($result, $i, 'repo_name');
+ $repodir = $repo_prefix.'/'.$repo_name;
+ if (util_is_valid_repository_name($repo_name)) {
+ system("rm -rf $repodir");
+ }
+ db_query_params ('DELETE FROM scm_secondary_repos WHERE group_id=$1 AND repo_name=$2 AND next_action = $3 AND plugin_id=$4',
+ array($project->getID(),
+ $repo_name,
+ SCM_EXTRA_REPO_ACTION_DELETE,
+ $this->getID()));
+ }
+ $this->regenApacheAuth($params);
}
function updateRepositoryList(&$params) {
return false;
}
- if (!$project->usesPlugin($this->name)) {
- return false;
- }
-
if ($params['mode'] == 'day') {
db_begin();
$usr_deletes = array();
$usr_commits = array();
- $repo = forge_get_config('repos_path', 'scmsvn') . '/' . $project->getUnixName();
- if (!is_dir($repo) || !is_file ("$repo/format")) {
+ $repo = forge_get_config('repos_path', 'scmsvn').'/'.$project->getUnixName().'/'.$project->getUnixName();
+ if (!is_dir ($repo) || !is_file ("$repo/format")) {
db_rollback();
return false;
}
xml_get_current_line_number($xml_parser));
db_rollback () ;
return false ;
- break;
}
}
$snapshot = forge_get_config('scm_snapshots_path').'/'.$group_name.'-scm-latest.tar'.util_get_compressed_file_extension();
$tarball = forge_get_config('scm_tarballs_path').'/'.$group_name.'-scmroot.tar'.util_get_compressed_file_extension();
- if (!$project->usesPlugin($this->name)) {
- return false;
- }
-
if (!$project->enableAnonSCM()) {
if (is_file($snapshot)) {
unlink($snapshot);
}
$toprepo = forge_get_config('repos_path', 'scmsvn');
- $repo = $toprepo . '/' . $project->getUnixName();
+ $repo = $toprepo.'/'.$group_name.'/'.$group_name;
if (!is_dir($repo) || !is_file ("$repo/format")) {
if (is_file($snapshot)) {
if ($tmp == '') {
return false;
}
+
$today = date('Y-m-d');
$dir = $project->getUnixName ()."-$today" ;
system("mkdir -p $tmp") ;
$times = array();
$revisions = array();
- $group_id = $params['group'];
- $project = group_get_object($group_id);
- if (!$project->usesPlugin($this->name)) {
+ $project = $this->checkParams($params);
+ if (!$project) {
+ return false;
+ }
+ if (isset($params['exclusive_area']) && ($params['exclusive_area'] != $this->name)) {
return false;
}
$start_time = $params['begin'];
$end_time = $params['end'];
- $xml_parser = xml_parser_create();
- xml_set_element_handler($xml_parser, "SVNPluginStartElement", "SVNPluginEndElement");
- xml_set_character_data_handler($xml_parser, "SVNPluginCharData");
-
- // Grab&parse commit log
- $protocol = forge_get_config('use_ssl', 'scmsvn') ? 'https://' : 'http://';
if ($project->enableAnonSCM()) {
$server_script = '/anonscm/svnlog';
} else {
return false;
}
}
- $script_url = $protocol . forge_get_config('scm_host')
- . $server_script
- .'?unix_group_name='.$project->getUnixName()
- .'&mode=date_range'
- .'&begin='.$params['begin']
- .'&end='.$params['end'];
- $ch = curl_init();
- curl_setopt($ch, CURLOPT_URL, $script_url);
- curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'curl2xml');
- curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
- curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
- curl_setopt($ch, CURLOPT_COOKIE, @$_SERVER['HTTP_COOKIE']); // for session validation
- curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); // for session validation
- curl_setopt($ch, CURLOPT_HTTPHEADER,
- array('X-Forwarded-For: '.$_SERVER['REMOTE_ADDR'])); // for session validation
- $body = curl_exec($ch);
- if ($body === false) {
- $this->setError(curl_error($ch));
- }
- curl_close($ch);
-
- // final checks
- if (!xml_parse($xml_parser, '', true))
- $this->setError('Unable to parse XML with error '
- . xml_error_string(xml_get_error_code($xml_parser))
- . ' on line ' . xml_get_current_line_number($xml_parser));
- xml_parser_free($xml_parser);
- if ($adds > 0 || $updates > 0 || $commits > 0 || $deletes > 0) {
- $i = 0;
- foreach ($messages as $message) {
- $result = array();
- $result['section'] = 'scm';
- $result['group_id'] = $group_id;
- $result['ref_id'] = 'browser.php?group_id='.$group_id;
- $result['description'] = htmlspecialchars($message).' (r'.$revisions[$i].')';
- $userObject = user_get_object_by_name($users[$i]);
- if (is_a($userObject, 'FFUser')) {
- $result['realname'] = util_display_user($userObject->getUnixName(), $userObject->getID(), $userObject->getRealName());
- } else {
- $result['realname'] = '';
+ $repo_list = $this->getRepositories($project);
+ $protocol = forge_get_config('use_ssl', 'scmsvn') ? 'https://' : 'http://';
+ foreach ($repo_list as $repo_name) {
+ $xml_parser = xml_parser_create();
+ xml_set_element_handler($xml_parser, "SVNPluginStartElement", "SVNPluginEndElement");
+ xml_set_character_data_handler($xml_parser, "SVNPluginCharData");
+
+ // Grab & parse commit log
+ $script_url = $protocol.$this->getBoxForProject($project)
+ . $this->web_port
+ . $server_script
+ .'?unix_group_name='.$project->getUnixName()
+ .'&repo_name='.$repo_name
+ .'&mode=date_range'
+ .'&begin='.$params['begin']
+ .'&end='.$params['end'];
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_URL, $script_url);
+ curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'curl2xml');
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, forge_get_config('use_ssl_verification'));
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, forge_get_config('use_ssl_verification'));
+ curl_setopt($ch, CURLOPT_COOKIE, @$_SERVER['HTTP_COOKIE']); // for session validation
+ curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); // for session validation
+ curl_setopt($ch, CURLOPT_HTTPHEADER,
+ array('X-Forwarded-For: '.$_SERVER['REMOTE_ADDR'])); // for session validation
+ $body = curl_exec($ch);
+ if ($body === false) {
+ $this->setError(curl_error($ch));
+ }
+ curl_close($ch);
+
+ // final checks
+ if (!xml_parse($xml_parser, '', true)) {
+ $this->setError('Unable to parse XML with error '
+ . xml_error_string(xml_get_error_code($xml_parser))
+ . ' on line ' . xml_get_current_line_number($xml_parser));
+ }
+ xml_parser_free($xml_parser);
+
+ if ($adds > 0 || $updates > 0 || $commits > 0 || $deletes > 0) {
+ $i = 0;
+ foreach ($messages as $message) {
+ $result = array();
+ $result['section'] = 'scm';
+ $result['group_id'] = $project->getID();
+ $result['ref_id'] = 'browser.php?group_id='.$project->getID().'&scm_plugin='.$this->name.'&repo_name='.$repo_name;
+ $result['description'] = htmlspecialchars($message).' (repository: '.$repo_name.' r'.$revisions[$i].')';
+ $userObject = user_get_object_by_name($users[$i]);
+ if (is_a($userObject, 'FFUser')) {
+ $result['realname'] = util_display_user($userObject->getUnixName(), $userObject->getID(), $userObject->getRealName());
+ } else {
+ $result['realname'] = '';
+ }
+ $result['activity_date'] = $times[$i];
+ $result['subref_id'] = '&commit='.$revisions[$i];
+ $params['results'][] = $result;
+ $i++;
}
- $result['activity_date'] = $times[$i];
- $result['subref_id'] = '&commit='.$revisions[$i];
- $params['results'][] = $result;
- $i++;
}
}
}
- if (!in_array($this->name, $params['ids'])) {
+ if (!in_array($this->name, $params['ids']) && ($project->enableAnonSCM() || session_loggedin())) {
$params['ids'][] = $this->name;
$params['texts'][] = _('Subversion Commits');
}
}
// Get latest commits for inclusion in a widget
- function getCommits($project, $user = null, $nbCommits) {
+ function getCommits($project, $user, $nbCommits) {
global $commits, $users, $adds, $updates, $messages, $times, $revisions, $deletes, $time_ok, $user_list, $last_message, $notimecheck, $xml_parser;
$commits = 0;
$users = array();
$notimecheck = true;
$revisionsArr = array();
if ($project->usesPlugin($this->name) && forge_check_perm('scm', $project->getID(), 'read')) {
- $xml_parser = xml_parser_create();
- xml_set_element_handler($xml_parser, "SVNPluginStartElement", "SVNPluginEndElement");
- xml_set_character_data_handler($xml_parser, "SVNPluginCharData");
-
// Grab&parse commit log
$protocol = forge_get_config('use_ssl', 'scmsvn') ? 'https://' : 'http://';
$u = session_get_user();
- if ($project->enableAnonSCM())
+ if ($project->enableAnonSCM()) {
$server_script = '/anonscm/svnlog';
- else
+ } else {
$server_script = '/authscm/'.$u->getUnixName().'/svnlog';
+ }
if ($user) {
$userunixname = $user->getUnixName();
$params = '&mode=latest_user&user_name='.$userunixname;
} else {
$params = '&mode=latest';
}
- $script_url = $protocol . forge_get_config('scm_host')
- . $server_script
- .'?unix_group_name='.$project->getUnixName()
- . $params
- .'&limit='.$nbCommits;
- $ch = curl_init();
- curl_setopt($ch, CURLOPT_URL, $script_url);
- curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'curl2xml');
- curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
- curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
- curl_setopt($ch, CURLOPT_COOKIE, $_SERVER['HTTP_COOKIE']); // for session validation
- curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); // for session validation
- curl_setopt($ch, CURLOPT_HTTPHEADER,
- array('X-Forwarded-For: '.$_SERVER['REMOTE_ADDR'])); // for session validation
- $body = curl_exec($ch);
- if ($body === false) {
- $this->setError(curl_error($ch));
- }
- curl_close($ch);
-
- // final checks
- if (!xml_parse($xml_parser, '', true))
- $this->setError('Unable to parse XML with error '
+ $repo_list = $this->getRepositories($project);
+ $i = 0;
+ foreach ($repo_list as $repo_name) {
+ $script_url = $protocol.$this->getBoxForProject($project)
+ . $this->web_port
+ . $server_script
+ .'?unix_group_name='.$project->getUnixName()
+ .'&repo_name='.$repo_name
+ . $params
+ .'&limit='.$nbCommits;
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_URL, $script_url);
+ curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'curl2xml');
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, forge_get_config('use_ssl_verification'));
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, forge_get_config('use_ssl_verification'));
+ curl_setopt($ch, CURLOPT_COOKIE, $_SERVER['HTTP_COOKIE']); // for session validation
+ curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); // for session validation
+ curl_setopt($ch, CURLOPT_HTTPHEADER,
+ array('X-Forwarded-For: '.$_SERVER['REMOTE_ADDR'])); // for session validation
+ $body = curl_exec($ch);
+ if ($body === false) {
+ $this->setError(curl_error($ch));
+ }
+ curl_close($ch);
+
+ $xml_parser = xml_parser_create();
+ xml_set_element_handler($xml_parser, "SVNPluginStartElement", "SVNPluginEndElement");
+ xml_set_character_data_handler($xml_parser, "SVNPluginCharData");
+ // final checks
+ if (!xml_parse($xml_parser, '', true)) {
+ $this->setError('Unable to parse XML with error '
. xml_error_string(xml_get_error_code($xml_parser))
. ' on line ' . xml_get_current_line_number($xml_parser));
- xml_parser_free($xml_parser);
+ }
+ xml_parser_free($xml_parser);
- if ($adds > 0 || $updates > 0 || $commits > 0 || $deletes > 0) {
- $i = 0;
- foreach ($messages as $message) {
- if ($user && ($users[$i] == $userunixname)) {
- $revisionsArr[$i]['pluginName'] = 'scmsvn';
- $revisionsArr[$i]['description'] = htmlspecialchars($message);
- $revisionsArr[$i]['commit_id'] = $revisions[$i];
- $revisionsArr[$i]['date'] = $times[$i];
- } else {
+ if ($adds > 0 || $updates > 0 || $commits > 0 || $deletes > 0) {
+ foreach ($messages as $message) {
$revisionsArr[$i]['pluginName'] = 'scmsvn';
$revisionsArr[$i]['description'] = htmlspecialchars($message);
$revisionsArr[$i]['commit_id'] = $revisions[$i];
+ $revisionsArr[$i]['repo_name'] = $repo_name;
$revisionsArr[$i]['date'] = $times[$i];
+ $i++;
}
- $i++;
}
}
}
return $revisionsArr;
}
- function get_scm_repo_list(&$params) {
+ function scm_add_repo(&$params) {
+ $project = $this->checkParams($params);
+ if (!$project) {
+ return false;
+ }
+
+ if (!isset($params['repo_name'])) {
+ return false;
+ }
+
+ if ($params['repo_name'] == $project->getUnixName()) {
+ $params['error_msg'] = _('Cannot create a secondary repository with the same name as the primary');
+ return false;
+ }
+
+ if (!util_is_valid_repository_name($params['repo_name'])) {
+ $params['error_msg'] = _('This repository name is not valid');
+ return false;
+ }
+
+ $result = db_query_params('SELECT count(*) AS count FROM scm_secondary_repos WHERE repo_name = $1 AND plugin_id=$2',
+ array($params['repo_name'], $this->getID()));
+ if (!$result) {
+ $params['error_msg'] = db_error();
+ return false;
+ }
+ if (db_result($result, 0, 'count')) {
+ $params['error_msg'] = sprintf(_('%s as repository name cannot be used'), $params['repo_name']);
+ return false;
+ }
+
+ // do to current implementation of multiple repositories in SVN : we need to check repo_name against project names and forbid it
+ $result = db_query_params('SELECT count(*) as count FROM groups WHERE unix_group_name = $1',
+ array($params['repo_name']));
+ if (!$result) {
+ $params['error_msg'] = db_error();
+ return false;
+ }
+ if (db_result($result, 0, 'count')) {
+ $params['error_msg'] = sprintf(_('%s as repository name cannot be used'), $params['repo_name']);
+ return false;
+ }
+
+ $description = '';
+ $clone = '';
+ if (isset($params['description'])) {
+ $description = $params['description'];
+ }
+ if (!$description) {
+ $description = "Subversion repository $params[repo_name] for project ".$project->getUnixName();
+ }
+ $result = db_query_params('INSERT INTO scm_secondary_repos (group_id, repo_name, description, clone_url, plugin_id) VALUES ($1, $2, $3, $4, $5)',
+ array($params['group_id'],
+ $params['repo_name'],
+ $description,
+ $clone,
+ $this->getID()));
+ if (!$result) {
+ $params['error_msg'] = db_error();
+ return false;
+ }
+
+ plugin_hook ("scm_admin_update", $params);
+ return true;
+ }
+
+ function get_scm_repo_list(&$params) {
if (array_key_exists('group_name',$params)) {
$unix_group_name = $params['group_name'];
} else {
continue;
}
$urls = array();
+ $project = group_get_object($arr['group_id']);
if (forge_get_config('use_dav', 'scmsvn')) {
- $urls[] = $protocol.'://'.forge_get_config('scm_host').'/anonscm/svn/'.$arr['unix_group_name'];
+ $urls[] = $protocol.'://'.$this->getBoxForProject($project).$this->web_port.'/anonscm/svn/'.$arr['unix_group_name'];
}
if (forge_get_config('use_ssh', 'scmsvn')) {
- $urls[] = 'svn://'.forge_get_config('scm_host').$this->svn_root_fs.'/'.$arr['unix_group_name'];
+ $urls[] = 'svn://'.$this->getBoxForProject($project).$this->svn_root_fs.'/'.$arr['unix_group_name'];
}
if (session_loggedin()) {
if (forge_get_config('use_dav', 'scmsvn')) {
- $urls[] = $protocol.'://'.forge_get_config('scm_host').'/authscm/'.$d.'/svn/'.$arr['unix_group_name'];
+ $urls[] = $protocol.'://'.$this->getBoxForProject($project).$this->web_port.'/authscm/'.$d.'/svn/'.$arr['unix_group_name'];
}
if (forge_get_config('use_ssh', 'scmsvn')) {
- $urls[] = 'svn+ssh://'.$d.'@' . forge_get_config('scm_host') . $this->svn_root_fs .'/'. $arr['unix_group_name'];
+ $urls[] = 'svn+ssh://'.$d.'@'.$this->getBoxForProject($project).$this->svn_root_fs .'/'. $arr['unix_group_name'];
}
}
$results[] = array('group_id' => $arr['group_id'],
}
}
- function get_scm_repo_info(&$params) {
+ function get_scm_repo_info(&$params) {
$rid = $params['repository_id'];
$e = explode('/',$rid);
if ($e[1] != 'svn') {
}
}
- function parse_scm_repo_activities(&$params) {
+ function parse_scm_repo_activities(&$params) {
$repos = array();
$res = db_query_params("SELECT unix_group_name, groups.group_id FROM groups
JOIN group_plugin ON (groups.group_id=group_plugin.group_id)
}
}
foreach ($tstamps as $t => $v) {
- $res = db_query_params("INSERT INTO scm_activities (group_id, plugin_id, repository_id, tstamp) VALUES ($1,$2,$3,$4)",
+ db_query_params("INSERT INTO scm_activities (group_id, plugin_id, repository_id, tstamp) VALUES ($1,$2,$3,$4)",
array($rdata['gid'],
$this->getID(),
$rdata['rid'],
}
}
}
+
+ function scm_admin_form(&$params) {
+ global $HTML;
+ $project = $this->checkParams($params);
+ if (!$project) {
+ return false;
+ }
+
+ session_require_perm('project_admin', $params['group_id']);
+ if (forge_get_config('allow_multiple_scm') && ($params['allow_multiple_scm'] > 1)) {
+ echo html_ao('div', array('id' => 'tabber-'.$this->name, 'class' => 'tabbertab'));
+ }
+
+ $project_name = $project->getUnixName();
+
+ $result = db_query_params('SELECT repo_name, description FROM scm_secondary_repos WHERE group_id=$1 AND next_action = $2 AND plugin_id=$3 ORDER BY repo_name',
+ array($params['group_id'],
+ SCM_EXTRA_REPO_ACTION_UPDATE,
+ $this->getID()));
+ if (!$result) {
+ $params['error_msg'] = db_error();
+ return false;
+ }
+ $existing_repos = array();
+ while($data = db_fetch_array($result)) {
+ $existing_repos[] = array('repo_name' => $data['repo_name'],
+ 'description' => $data['description']);
+ }
+ if (empty($existing_repos)) {
+ echo $HTML->information(_('No extra Subversion repository for project').' '.$project_name);
+ } else {
+ echo html_e('h2', array(), sprintf(ngettext('Extra Subversion repository for project %1$s',
+ 'Extra Subversion repositories for project %1$s',
+ count($existing_repos)), $project_name));
+ $titleArr = array(_('Repository name'), ('Initial repository description'), _('Delete'));
+ echo $HTML->listTableTop($titleArr);
+ foreach ($existing_repos as $repo) {
+ $cells = array();
+ $cells[][] = html_e('kbd', array(), $repo['repo_name']);
+ $cells[][] = $repo['description'];
+ $deleteForm = $HTML->openForm(array('name' => 'form_delete_repo_'.$repo['repo_name'], 'action' => getStringFromServer('PHP_SELF'), 'method' => 'post'));
+ $deleteForm .= html_e('input', array('type' => 'hidden', 'name' => 'group_id', 'value' => $params['group_id']));
+ $deleteForm .= html_e('input', array('type' => 'hidden', 'name' => 'delete_repository', 'value' => 1));
+ $deleteForm .= $HTML->html_input('scm_plugin_id', '', '', 'hidden', $this->getID());
+ $deleteForm .= html_e('input', array('type' => 'hidden', 'name' => 'repo_name', 'value' => $repo['repo_name']));
+ $deleteForm .= html_e('input', array('type' => 'submit', 'name' => 'submit', 'value' => _('Delete')));
+ $deleteForm .= $HTML->closeForm();
+ $cells[][] = $deleteForm;
+ echo $HTML->multiTableRow(array(), $cells);
+ }
+ echo $HTML->listTableBottom();
+ }
+
+ echo html_e('h2', array(), _('Create new Subversion repository for project').' '.$project_name);
+ echo $HTML->openForm(array('name' => 'form_create_repo', 'action' => getStringFromServer('PHP_SELF'), 'method' => 'post'));
+ echo html_e('input', array('type' => 'hidden', 'name' => 'group_id', 'value' => $params['group_id']));
+ echo html_e('input', array('type' => 'hidden', 'name' => 'create_repository', 'value' => 1));
+ echo html_e('p', array(), html_e('strong', array(), _('Repository name')._(':')).utils_requiredField().html_e('br').
+ html_e('input', array('type' => 'text', 'required' => 'required', 'size' => 20, 'name' => 'repo_name', 'value' => '')));
+ echo html_e('p', array(), html_e('strong', array(), _('Description')._(':')).html_e('br').
+ html_e('input', array('type' => 'text', 'size' => 60, 'name' => 'description', 'value' => '')));
+ echo html_e('input', array('type' => 'submit', 'name' => 'cancel', 'value' => _('Cancel')));
+ echo html_e('input', array('type' => 'submit', 'name' => 'submit', 'value' => _('Submit')));
+ echo $HTML->closeForm();
+
+ if ($project->usesPlugin('scmhook')) {
+ $scmhookPlugin = plugin_get_object('scmhook');
+ $scmhookPlugin->displayScmHook($project->getID(), $this->name);
+ }
+ if (forge_get_config('allow_multiple_scm') && ($params['allow_multiple_scm'] > 1)) {
+ echo html_ac(html_ap() - 1);
+ }
+ }
+
+ function getRepositories($group, $autoinclude = true) {
+ $repoarr = array();
+ if ($autoinclude) {
+ $repoarr[] = $group->getUnixName();
+ }
+ $result = db_query_params('SELECT repo_name FROM scm_secondary_repos WHERE group_id = $1 AND next_action = $2 AND plugin_id = $3 ORDER BY repo_name',
+ array($group->getID(),
+ SCM_EXTRA_REPO_ACTION_UPDATE,
+ $this->getID()));
+ while ($arr = db_fetch_array($result)) {
+ $repoarr[] = $arr['repo_name'];
+ }
+ return $repoarr;
+ }
+
+ function getGroupIdFromSecondReponame($repo_name) {
+ $result = db_query_params('SELECT scm_secondary_repos.group_id FROM scm_secondary_repos, groups WHERE scm_secondary_repos.group_id = groups.group_id AND repo_name = $1 AND plugin_id = $2 AND next_action = $3', array($repo_name, $this->getID(), SCM_EXTRA_REPO_ACTION_UPDATE));
+ $arr = db_fetch_array($result);
+ return $arr['group_id'];
+ }
}
// End of class, helper functions now
} else {
$time_ok = false;
if (!isset($notimecheck)) {
- if ($last_user !== '') // empty in e.g. tags from cvs2svn
+ if ($last_user !== '') { // empty in e.g. tags from cvs2svn
$usr_commits[$last_user]--;
+ }
$commits--;
}
}
function curl2xml($ch, $data) {
global $xml_parser;
- if (!xml_parse($xml_parser, $data, false))
+ if (!xml_parse($xml_parser, $data, false)) {
exit_error('Unable to parse XML with error '
. xml_error_string(xml_get_error_code($xml_parser))
. ' on line ' . xml_get_current_line_number($xml_parser),
'activity');
+ }
return strlen($data);
}
// Local Variables: