* USA
*/
-class BzrPlugin extends SCM {
+class BzrPlugin extends SCMPlugin {
function BzrPlugin () {
global $gfconfig;
- $this->SCM () ;
+ $this->SCMPlugin () ;
$this->name = 'scmbzr';
$this->text = 'Bazaar';
- $this->hooks[] = 'scm_page';
- $this->hooks[] = 'scm_admin_update';
- $this->hooks[] = 'scm_admin_page';
- $this->hooks[] = 'scm_stats';
- $this->hooks[] = 'scm_plugin';
- $this->hooks[] = 'scm_createrepo';
+ $this->hooks[] = 'scm_generate_snapshots' ;
+ $this->hooks[] = 'scm_browser_page';
+ $this->hooks[] = 'scm_update_repolist' ;
+ $this->hooks[] = 'scm_gather_stats' ;
require_once $gfconfig.'plugins/scmbzr/config.php' ;
$this->default_bzr_server = $default_bzr_server ;
- $this->enabled_by_default = $enabled_by_default ;
- $this->bzr_root = $bzr_root;
+ if (isset ($bzr_root)) {
+ $this->bzr_root = $bzr_root;
+ } else {
+ $this->bzr_root = $GLOBALS['sys_chroot'].'/scmrepos/bzr' ;
+ }
+ $this->main_branch_names = array () ;
+ $this->main_branch_names[] = 'trunk' ;
+ $this->main_branch_names[] = 'master' ;
+ $this->main_branch_names[] = 'main' ;
+ $this->main_branch_names[] = 'head' ;
+ $this->main_branch_names[] = 'HEAD' ;
+
$this->register () ;
}
return $this->default_bzr_server ;
}
- function CallHook ($hookname, $params) {
- global $HTML ;
-
- switch ($hookname) {
- case 'scm_page':
- $group_id = $params['group_id'] ;
- $this->getPage ($group_id) ;
- break ;
- case 'scm_admin_update':
- $this->AdminUpdate ($params) ;
- break ;
- case 'scm_admin_page':
- $this->getAdminPage ($params) ;
- break ;
- case 'scm_stats':
- $this->getStats ($params) ;
- break;
- case 'scm_createrepo':
- $this->createOrUpdateRepo ($params) ;
- break;
- case 'scm_plugin':
- $scm_plugins=& $params['scm_plugins'];
- $scm_plugins[]=$this->name;
- break;
- default:
- // Forgot something
- }
- }
-
- function getPage ($group_id) {
- global $HTML, $sys_scm_snapshots_path;
-
- $project =& group_get_object($group_id);
- if (!$project || !is_object($project)) {
- return false;
- } elseif ($project->isError()) {
- return false;
+ function printShortStats ($params) {
+ $project = $this->checkParams ($params) ;
+ if (!$project) {
+ return false ;
}
-
- if ($project->usesPlugin ($this->name)) {
- // Bazaar browser links must be displayed if
- // project enables anonymous Bazaar
- $displayBzrBrowser = $project->enableAnonSCM();
-
- // Table for summary info
- print ('<table width="100%">
- <tr valign="top">
- <td width="65%">') ;
- print _('<p>Documentation for Bazaar (sometimes referred to as "bzr") is available <a href="http://doc.bazaar-vcs.org/latest/en/user-guide/index.html">here</a>.</p>');
-
- // Anonymous Bazaar Instructions
- if ($project->enableAnonSCM()) {
- print _("<p><b>Anonymous Bazaar Access</b></p><p>This project's Bazaar repository can be accessed anonymously through HTTP.</p>");
- print '<p>';
- print _("A list of available branches can be obtained with the following command:") ;
- print "<br />" ;
- print '<tt>bzr branches http://' . $project->getSCMBox(). '/' . $this->svn_root .'/'. $project->getUnixName() .'</tt>';
- print '</p>';
- print '<p>';
- print _("To check out one of these branches:") ;
- print "<br />" ;
- print '<tt>bzr checkout http://' . $project->getSCMBox(). '/' . $this->svn_root .'/'. $project->getUnixName() .'<i>'._('branchname').'</i></tt>' ;
- print '</p>';
- }
-
- // Developer Access
- echo _('<p><b>Developer Bazaar Access via SSH</b></p><p>Only project developers can access the Bazaar branches tree via this method. SSH must be installed on your client machine. Substitute <i>developername</i> with the proper values. Enter your site password when prompted.</p>');
- print '<p><tt>bzr checkout bzr+ssh://<i>'._('developername').'</i>@' . $project->getSCMBox() . '/'. $this->svn_root .'/'. $project->getUnixName().'/'._('branchname').'</tt></p>' ;
- // Bazaar Snapshot
- if ($displaySvnBrowser) {
- $filename=$project->getUnixName().'-scm-latest.tar.gz';
- if (file_exists($sys_scm_snapshots_path.'/'.$filename)) {
- print '<p>[' ;
- print util_make_link ("/snapshots.php?group_id=$group_id",
- _('Download The Nightly Bazaar Tree Snapshot')
- ) ;
- print ']</p>';
- }
+ if ($project->usesPlugin($this->name)) {
+ $result = db_query_params('SELECT sum(commits) AS commits, sum(adds) AS adds FROM stats_cvs_group WHERE group_id=$1',
+ array ($project->getID())) ;
+ $commit_num = db_result($result,0,'commits');
+ $add_num = db_result($result,0,'adds');
+ if (!$commit_num) {
+ $commit_num=0;
}
-
- print '</td><td width="35%" valign="top">' ;
- // Bazaar Browsing
-
- echo $HTML->boxTop(_('Repository History'));
- echo _('Not implemented yet');
- /* echo $this->getDetailedStats(array('group_id'=>$group_id)).'<p>';
- if ($displaySvnBrowser) {
- echo _('<b>Browse the Bazaar Tree</b><p>Browsing the Bazaar tree gives you a great view into the current status of this project\'s code. You may also view the complete histories of any file in the repository.</p>');
- echo '<p>[' ;
- echo util_make_link ("/scm/viewvc.php/?root=".$project->getUnixName(),
- _('Browse Bazaar Repository')
- ) ;
- echo ']</p>' ;
- }
- */
- echo $HTML->boxBottom();
- print '</td></tr></table>' ;
+ if (!$add_num) {
+ $add_num=0;
+ }
+ echo ' (Bazaar: '.sprintf(_('<strong>%1$s</strong> commits, <strong>%2$s</strong> adds'), number_format($commit_num, 0), number_format($add_num, 0)).")";
}
}
- function AdminUpdate ($params) {
- $group =& group_get_object($params['group_id']);
- if (!$group || !is_object($group)) {
- return false;
- } elseif ($group->isError()) {
- return false;
- }
-
- if ( $group->usesPlugin ( $this->name ) ) {
- if ($params['scmbzr_enable_anon_bzr']) {
- $group->SetUsesAnonSCM(true);
- } else {
- $group->SetUsesAnonSCM(false);
- }
- }
+ function getBlurb () {
+ return _('<p>Documentation for Bazaar (sometimes referred to as "bzr") is available <a href="http://bazaar-vcs.org/Documentation">here</a>.</p>') ;
}
- // This function is used to render checkboxes below
- function c($v) {
- if ($v) {
- return 'checked="checked"';
- } else {
- return '';
- }
+ function getInstructionsForAnon ($project) {
+ $b = _('<p><b>Anonymous Bazaar Access</b></p><p>This project\'s Bazaar repository can be checked out through anonymous access with the following command.</p>');
+ $b .= '<p>' ;
+ $b .= '<tt>bzr checkout '.util_make_url ('/anonscm/bzr/'.$project->getUnixName().'/').'</tt><br />';
+ $b .= '</p>';
+ return $b ;
}
- function getAdminPage ($params) {
- $group =& group_get_object($params['group_id']);
- if ( $group->usesPlugin ( $this->name ) && $group->isPublic()) {
- ?>
- <p><input type="checkbox" name="scmbzr_enable_anon_bzr" value="1" <?php echo $this->c($group->enableAnonSCM()); ?> /><strong><?php echo _('Enable Anonymous Access') ?></strong></p>
- <?php
- }
+ function getInstructionsForRW ($project) {
+ $b = '' ;
+ $b .= _('<p><b>Developer Bazaar Access via SSH</b></p><p>Only project developers can access the Bazaar branches via this method. SSH must be installed on your client machine. Substitute <i>developername</i> with the proper values. Enter your site password when prompted.</p>');
+ $b .= '<p><tt>bzr checkout bzr+ssh://<i>'._('developername').'</i>@' . $project->getSCMBox() . $this->bzr_root .'/'. $project->getUnixName().'/'._('branchname').'</tt></p>' ;
+
+ return $b ;
}
- function getStats ($params) {
- $group_id = $params['group_id'] ;
- $project =& group_get_object($group_id);
- if (!$project || !is_object($project)) {
- return false;
- } elseif ($project->isError()) {
- return false;
- }
-
- if ($project->usesPlugin ($this->name)) {
- list($commit_num, $add_num) = $this->getTotalStats($group_id);
- echo ' (Bazaar: '.sprintf(_('<strong>%1$s</strong> updates, <strong>%2$s</strong> adds'), number_format($commit_num, 0), number_format($add_num, 0)).')';
- }
+ function getSnapshotPara ($project) {
+ return ;
}
- // Get the total stats for a group
- function getTotalStats($group_id) {
- $result = db_query("
- SELECT SUM(commits) AS commits, SUM(adds) AS adds
- FROM stats_cvs_group
- WHERE group_id='$group_id'");
- $commit_num = db_result($result,0,0);
- $add_num = db_result($result,0,1);
- if (!$commit_num) {
- $commit_num=0;
- }
- if (!$add_num) {
- $add_num=0;
- }
- return array($commit_num, $add_num);
+ function getBrowserLinkBlock ($project) {
+ global $HTML ;
+ $b = $HTML->boxMiddle(_('Bazaar Repository Browser'));
+ $b .= _('<p>Browsing the Bazaar 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.</p>');
+ $b .= '<p>[' ;
+ $b .= util_make_link ("/scm/browser.php?group_id=".$project->getID(),
+ _('Browse Bazaar Repository')
+ ) ;
+ $b .= ']</p>' ;
+ return $b ;
}
- function getDetailedStats ($params) {
- global $HTML;
- $group_id = $params['group_id'] ;
-
- $result = db_query('
- SELECT u.realname, u.user_name, u.user_id, sum(commits) as commits, sum(adds) as adds, sum(adds+commits) as combined
- FROM stats_cvs_user s, users u
- WHERE group_id=\''.$group_id.'\' AND s.user_id=u.user_id AND (commits>0 OR adds >0)
- GROUP BY group_id, realname, user_name, u.user_id
- ORDER BY combined DESC, realname;
- ');
-
- if (db_numrows($result) > 0) {
- $tableHeaders = array(
- _('Name'),
- _('Adds'),
- _('Updates')
- );
- echo $HTML->listTableTop($tableHeaders);
-
- $i = 0;
- $total = array('adds' => 0, 'commits' => 0);
-
- while($data = db_fetch_array($result)) {
- echo '<tr '. $HTML->boxGetAltRowStyle($i) .'>';
- echo '<td width="50%">' ;
- echo util_make_link_u ($data['user_name'], $data['user_id'], $data['realname']) ;
- echo '</td><td width="25%" align="right">'.$data['adds']. '</td>'.
- '<td width="25%" align="right">'.$data['commits'].'</td></tr>';
- $total['adds'] += $data['adds'];
- $total['commits'] += $data['commits'];
- $i++;
- }
- list($commit_num, $add_num) = $this->getTotalStats($group_id);
- if ($commit_num > $total['commits'] ||
- $add_num > $total['adds']) {
- echo '<tr '. $HTML->boxGetAltRowStyle($i) .'>';
- echo '<td width="50%">' .
- _('Unknown') .
- '</td><td width="25%" align="right">'.
- ($add_num - $total['adds']) . '</td>'.
- '<td width="25%" align="right">'.
- ($commit_num - $total['commits']) .
- '</td></tr>';
- $i++;
- }
- echo '<tr '. $HTML->boxGetAltRowStyle($i) .'>';
- echo '<td width="50%"><strong>'._('Total').':</strong></td>'.
- '<td width="25%" align="right"><strong>'.$add_num. '</strong></td>'.
- '<td width="25%" align="right"><strong>'.$commit_num.'</strong></td>';
- echo '</tr>';
- echo $HTML->listTableBottom();
- echo '<hr size="1" />';
- }
+ function getStatsBlock ($project) {
+ return ;
}
- function createOrUpdateRepo ($params) {
- $group_id = $params['group_id'] ;
+ function printBrowserPage ($params) {
+ global $HTML;
- $project =& group_get_object($group_id);
- if (!$project || !is_object($project)) {
- return false;
- } elseif ($project->isError()) {
- return false;
+ $project = $this->checkParams ($params) ;
+ if (!$project) {
+ return false ;
+ }
+
+ if ($project->usesPlugin ($this->name)) {
+ if ($this->browserDisplayable ($project)) {
+ print '<iframe src="'.util_make_url ("/scm/loggerhead/".$project->getUnixName()).'" frameborder="no" width=100% height=700></iframe>' ;
+ }
+ }
+ }
+
+ function createOrUpdateRepo ($params) {
+ $project = $this->checkParams ($params) ;
+ if (!$project) {
+ return false ;
}
-
+
if (! $project->usesPlugin ($this->name)) {
return false;
}
}
if (!$repo_exists) {
- system ("bzr init-repo --no-trees $repo") ;
+ system ("mkdir -p $repo") ;
+ system ("bzr init-repo --no-trees $repo >/dev/null") ;
+ system ("find $repo -type d | xargs chmod g+s") ;
}
system ("chgrp -R $unix_group $repo") ;
if ($project->enableAnonSCM()) {
- system ("chmod -R g+wXs,o+rX-w $repo") ;
+ system ("chmod -R g+wX,o+rX-w $repo") ;
} else {
- system ("chmod -R g+wXs,o-rwx $repo") ;
+ system ("chmod -R g+wX,o-rwx $repo") ;
}
}
+
+ function updateRepositoryList ($params) {
+ $groups = $this->getGroups () ;
+
+ $dir = '/var/lib/gforge/plugins/scmbzr/public-repositories' ;
+
+ $oldlist = array () ;
+ $dh = opendir ($dir) ;
+ while (($file = readdir($dh)) !== false) {
+ if ($file != '.' && $file != '..') {
+ $oldlist[] = $file ;
+ }
+ }
+ closedir($dh) ;
+ sort ($oldlist) ;
+
+ $newlist = array () ;
+ foreach ($groups as $project) {
+ if ($this->browserDisplayable ($project)) {
+ $newlist[] = $project->getUnixName() ;
+ }
+ }
+ sort ($newlist) ;
+
+ $dellist = array () ;
+ $createlist = array () ;
+
+ while (count ($oldlist) > 0 && count ($newlist) > 0) {
+ $o = $oldlist[0] ;
+ $n = $newlist[0] ;
+ if ($o > $n) {
+ $createlist[] = array_shift ($newlist) ;
+ } elseif ($o < $n) {
+ $dellist[] = array_shift ($oldlist) ;
+ } else {
+ array_shift ($newlist) ;
+ array_shift ($oldlist) ;
+ }
+ }
+ $dellist = array_merge ($dellist, $oldlist) ;
+ $createlist = array_merge ($createlist, $newlist) ;
+
+ foreach ($dellist as $del) {
+ unlink ($dir . '/' . $del) ;
+ }
+ foreach ($createlist as $create) {
+ symlink ($this->bzr_root . '/' . $create, $dir . '/' . $create) ;
+ }
+ }
+
+ function gatherStats ($params) {
+ $project = $this->checkParams ($params) ;
+ if (!$project) {
+ return false ;
+ }
+
+ if (! $project->usesPlugin ($this->name)) {
+ return false;
+ }
+
+ if ($params['mode'] == 'day') {
+ db_begin();
+
+ $year = $params ['year'] ;
+ $month = $params ['month'] ;
+ $day = $params ['day'] ;
+ $month_string = sprintf( "%04d%02d", $year, $month );
+ $start_time = gmmktime( 0, 0, 0, $month, $day, $year);
+ $end_time = $start_time + 86400;
+
+ $date = sprintf ("%04d-%02d-%02d", $year, $month, $day);
+
+ $updates = 0 ;
+ $adds = 0 ;
+ $usr_updates = array () ;
+ $usr_adds = array () ;
+
+ $toprepo = $this->bzr_root ;
+ $repo = $toprepo . '/' . $project->getUnixName() ;
+
+ $branch = $this->findMainBranch ($project) ;
+
+ if ($branch == '') {
+ db_rollback () ;
+ return false ;
+ }
+
+ $pipe = popen ("bzr log file://$repo/$branch --long --verbose 2> /dev/null", 'r' ) ;
+
+ // cleaning stats_cvs_* table for the current day
+ $res = db_query_params ('DELETE FROM stats_cvs_group WHERE month=$1 AND day=$2 AND group_id=$3',
+ array ($month_string,
+ $day,
+ $project->getID())) ;
+ if(!$res) {
+ echo "Error while cleaning stats_cvs_group\n" ;
+ db_rollback () ;
+ return false ;
+ }
+
+ $res = db_query_params ('DELETE FROM stats_cvs_user WHERE month=$1 AND day=$2 AND group_id=$3',
+ array ($month_string,
+ $day,
+ $project->getID())) ;
+ if(!$res) {
+ echo "Error while cleaning stats_cvs_user\n" ;
+ db_rollback () ;
+ return false ;
+ }
+
+ // Analyzing history stream
+ $sep = '------------------------------------------------------------' ;
+ $currev = '' ;
+ $curuser = '' ;
+ $curdate = '' ;
+ $state = '' ;
+ $curadds = 0 ;
+ $curupdates = 0 ;
+ while (! feof ($pipe) &&
+ $line = rtrim (fgets ($pipe))) {
+ if ($line == $sep) {
+ if ($curdate == $date) {
+ $adds = $adds + $curadds ;
+ $updates = $updates + $curupdates ;
+ }
+ if ($curdate != '' && $curdate < $date) {
+ fclose ($pipe) ;
+ break ;
+ }
+ $currev = '' ;
+ $curuser = '' ;
+ $curdate = '' ;
+ $state = '' ;
+ $curadds = 0 ;
+ $curupdates = 0 ;
+ } elseif (preg_match( '/^revno: ([0-9]+)$/', $line, $matches)) {
+ $currev = $matches[1] ;
+ } elseif (preg_match( '/^committer: (.*)$/', $line, $matches)) {
+ $curuser = $matches[1] ;
+ } elseif (preg_match( '/^timestamp: ... (\d\d\d\d-\d\d-\d\d)/', $line, $matches)) {
+ $curdate = $matches[1] ;
+ } elseif (preg_match( '/^modified:/', $line, $matches)) {
+ $state = 'modified' ;
+ } elseif (preg_match( '/^renamed:/', $line, $matches)) {
+ $state = 'renamed' ;
+ } elseif (preg_match( '/^removed:/', $line, $matches)) {
+ $state = 'removed' ;
+ } elseif (preg_match( '/^added/', $line, $matches)) {
+ $state = 'added' ;
+ } else {
+ switch ($state) {
+ case 'modified':
+ $curupdates++ ;
+ break ;
+ case 'added':
+ $curadds++ ;
+ break ;
+ }
+ }
+ }
+ if ($curdate == $date) {
+ $adds = $adds + $curadds ;
+ $updates = $updates + $curupdates ;
+ }
+
+ // inserting group results in stats_cvs_groups
+ if ($updates > 0 || $adds > 0) {
+ if (!db_query_params ('INSERT INTO stats_cvs_group (month,day,group_id,checkouts,commits,adds) VALUES ($1,$2,$3,$4,$5,$6)',
+ array ($month_string,
+ $day,
+ $project->getID(),
+ 0,
+ $updates,
+ $adds))) {
+ echo "Error while inserting into stats_cvs_group\n" ;
+ db_rollback () ;
+ return false ;
+ }
+ }
+
+ // building the user list
+ $user_list = array_unique( array_merge( array_keys( $usr_adds ), array_keys( $usr_updates ) ) );
+
+ foreach ( $user_list as $user ) {
+ // trying to get user id from user name
+ $u = &user_get_object_by_name ($user) ;
+ if ($u) {
+ $user_id = $u->getID();
+ } else {
+ continue;
+ }
+
+ $uu = $usr_updates[$user] ? $usr_updates[$user] : 0 ;
+ $ua = $usr_adds[$user] ? $usr_adds[$user] : 0 ;
+ if ($uu > 0 || $ua > 0) {
+ if (!db_query_params ('INSERT INTO stats_cvs_user (month,day,group_id,user_id,commits,adds) VALUES ($1,$2,$3,$4,$5,$6)',
+ array ($month_string,
+ $day,
+ $project->getID(),
+ $user_id,
+ $uu,
+ $ua))) {
+ echo "Error while inserting into stats_cvs_user\n" ;
+ db_rollback () ;
+ return false ;
+ }
+ }
+ }
+ }
+ db_commit();
+ }
+
+ function findMainBranch ($project) {
+ $toprepo = $this->bzr_root ;
+ $repo = $toprepo . '/' . $project->getUnixName() ;
+
+ $branch = '' ;
+
+ foreach ($this->main_branch_names as $bname) {
+ system ("bzr ls file://$repo/$bname > /dev/null 2>&1", $code) ;
+ if ($code == 0) {
+ $branch = $bname ;
+ break ;
+ }
+ }
+ return $branch;
+ }
+
+ function generateSnapshots ($params) {
+ global $sys_scm_snapshots_path ;
+ global $sys_scm_tarballs_path ;
+
+ $project = $this->checkParams ($params) ;
+ if (!$project) {
+ return false ;
+ }
+
+ $group_name = $project->getUnixName() ;
+
+ $snapshot = $sys_scm_snapshots_path.'/'.$group_name.'-scm-latest.tar.gz';
+ $tarball = $sys_scm_tarballs_path.'/'.$group_name.'-scmroot.tar.gz';
+
+ if (! $project->usesPlugin ($this->name)) {
+ return false;
+ }
+
+ if (! $project->enableAnonSCM()) {
+ unlink ($snapshot) ;
+ unlink ($tarball) ;
+ return false;
+ }
+
+ $toprepo = $this->bzr_root ;
+ $repo = $toprepo . '/' . $project->getUnixName() ;
+
+ if (!is_dir ($repo) || !is_file ("$repo/format")) {
+ unlink ($snapshot) ;
+ unlink ($tarball) ;
+ return false ;
+ }
+
+ $tmp = trim (`mktemp -d`) ;
+ if ($tmp == '') {
+ return false ;
+ }
+ $today = date ('Y-m-d') ;
+ $branch = $this->findMainBranch ($project) ;
+ if ($branch != '') {
+ system ("bzr export --root=$group_name-scm-$today $tmp/snapshot.tar.gz $repo/$bname") ;
+ chmod ("$tmp/snapshot.tar.gz", 0644) ;
+ copy ("$tmp/snapshot.tar.gz", $snapshot) ;
+ unlink ("$tmp/snapshot.tar.gz") ;
+ system ("rm -rf $tmp/$dir") ;
+ } else {
+ unlink ($snapshot) ;
+ }
+
+ system ("tar czCf $toprepo $tmp/tarball.tar.gz " . $project->getUnixName()) ;
+ chmod ("$tmp/tarball.tar.gz", 0644) ;
+ copy ("$tmp/tarball.tar.gz", $tarball) ;
+ unlink ("$tmp/tarball.tar.gz") ;
+ system ("rm -rf $tmp") ;
+ }
}
// Local Variables: