2 /** FusionForge CVS plugin
4 * Copyright 2004-2009, Roland Mas
6 * This file is part of FusionForge.
8 * FusionForge is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published
10 * by the Free Software Foundation; either version 2 of the License,
11 * or (at your option) any later version.
13 * FusionForge is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with FusionForge; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
24 class CVSPlugin extends SCMPlugin {
25 function CVSPlugin () {
28 global $cvsdir_prefix ;
30 $this->name = 'scmcvs';
32 $this->hooks[] = 'scm_browser_page';
33 $this->hooks[] = 'scm_generate_snapshots' ;
34 $this->hooks[] = 'scm_gather_stats' ;
36 require_once $GLOBALS['gfconfig'].'plugins/scmcvs/config.php' ;
38 $this->default_cvs_server = $default_cvs_server ;
40 $this->cvs_root = $cvs_root;
41 } elseif ($cvsdir_prefix) {
42 $this->cvs_root = $cvsdir_prefix;
44 $this->cvs_root = forge_get_config('chroot').'/scmrepos/cvs' ;
50 function getDefaultServer() {
51 return $this->default_cvs_server;
54 function printShortStats ($params) {
55 $project = $this->checkParams ($params) ;
60 if ($project->usesPlugin($this->name)) {
61 $result = db_query_params('SELECT sum(commits) AS commits, sum(adds) AS adds FROM stats_cvs_group WHERE group_id=$1',
62 array ($project->getID())) ;
63 $commit_num = db_result($result,0,'commits');
64 $add_num = db_result($result,0,'adds');
71 echo ' (CVS: '.sprintf(_('<strong>%1$s</strong> commits, <strong>%2$s</strong> adds'), number_format($commit_num, 0), number_format($add_num, 0)).")";
75 function getBlurb () {
76 return _('<p>CVS documentation is available <a href="http://cvsbook.red-bean.com/">here</a>.</p>');
79 function getInstructionsForAnon ($project) {
80 $cvsrootend = $project->getSCMBox().':'.$this->cvs_root.'/'.$project->getUnixName();
81 $b = _('<p><b>Anonymous CVS Access</b></p><p>This project\'s CVS repository can be checked out through anonymous (pserver) CVS with the following instruction set. The module you wish to check out must be specified as the <i>modulename</i>. When prompted for a password for <i>anonymous</i>, simply press the Enter key.</p>');
83 <tt>cvs -d :pserver:anonymous@' . $cvsrootend.' login</tt><br/>
84 <tt>cvs -d :pserver:anonymous@' . $cvsrootend.' checkout <em>'._('modulename').'</em></tt>
90 function getInstructionsForRW ($project) {
91 $cvsrootend = $project->getSCMBox().':'.$this->cvs_root.'/'.$project->getUnixName();
92 if (session_loggedin()) {
93 $u =& user_get_object(user_getid()) ;
94 $d = $u->getUnixName() ;
95 $b = _('<p><b>Developer CVS Access via SSH</b></p><p>Only project developers can access the CVS tree via this method. SSH must be installed on your client machine. Substitute <i>modulename</i> with the proper value. Enter your site password when prompted.</p>');
97 <tt>export CVS_RSH=ssh</tt><br/>
98 <tt>cvs -d :ext:'.$d.'@'.$cvsrootend.' checkout <em>'._('modulename').'</em></tt>
101 $b = _('<p><b>Developer CVS Access via SSH</b></p><p>Only project developers can access the CVS tree via this method. SSH must be installed on your client machine. Substitute <i>modulename</i> and <i>developername</i> with the proper values. Enter your site password when prompted.</p>');
103 <tt>export CVS_RSH=ssh</tt><br/>
104 <tt>cvs -d :ext:<em>'._('developername').'</em>@'.$cvsrootend.' checkout <em>'._('modulename').'</em></tt>
110 function getSnapshotPara ($project) {
113 $filename = $project->getUnixName().'-scm-latest.tar.gz';
114 if (file_exists(forge_get_config('scm_snapshots_path').'/'.$filename)) {
116 $b .= util_make_link ("/snapshots.php?group_id=".$project->getID(),
117 _('Download the nightly snapshot')
124 function getBrowserLinkBlock ($project) {
126 $b = $HTML->boxMiddle(_('CVS Repository Browser'));
127 $b .= _('<p>Browsing the CVS 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>');
129 $b .= util_make_link ("/scm/browser.php?group_id=".$project->getID(),
130 _('Browse CVS Repository')
136 function getStatsBlock ($project) {
140 $result = db_query_params('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=$1 AND s.user_id=u.user_id AND (commits>0 OR adds >0) GROUP BY u.user_id, realname, user_name, u.user_id ORDER BY combined DESC, realname',
141 array ($project->getID()));
143 if (db_numrows($result) > 0) {
144 $b .= $HTML->boxMiddle(_('Repository Statistics'));
146 $tableHeaders = array(
151 $b .= $HTML->listTableTop($tableHeaders);
154 $total = array('adds' => 0, 'commits' => 0);
156 while($data = db_fetch_array($result)) {
157 $b .= '<tr '. $HTML->boxGetAltRowStyle($i) .'>';
158 $b .= '<td width="50%">' ;
159 $b .= util_make_link_u ($data['user_name'], $data['user_id'], $data['realname']) ;
160 $b .= '</td><td width="25%" align="right">'.$data['adds']. '</td>'.
161 '<td width="25%" align="right">'.$data['commits'].'</td></tr>';
162 $total['adds'] += $data['adds'];
163 $total['commits'] += $data['commits'];
166 $b .= '<tr '. $HTML->boxGetAltRowStyle($i) .'>';
167 $b .= '<td width="50%"><strong>'._('Total').':</strong></td>'.
168 '<td width="25%" align="right"><strong>'.$total['adds']. '</strong></td>'.
169 '<td width="25%" align="right"><strong>'.$total['commits'].'</strong></td>';
171 $b .= $HTML->listTableBottom();
177 function printBrowserPage ($params) {
180 $project = $this->checkParams ($params) ;
185 if ($project->usesPlugin ($this->name)) {
186 if ($this->browserDisplayable ($project)) {
187 print '<iframe src="'.util_make_url ("/scm/viewvc.php/?root=".$project->getUnixName()).'" frameborder="no" width=100% height=700></iframe>' ;
192 function createOrUpdateRepo ($params) {
193 $project = $this->checkParams ($params) ;
198 if (! $project->usesPlugin ($this->name)) {
202 $repo = $this->cvs_root . '/' . $project->getUnixName() ;
203 $locks_dir = $this->cvs_root . '/cvs-locks/' . $project->getUnixName() ;
204 $unix_group = 'scm_' . $project->getUnixName() ;
206 $repo_exists = false ;
207 if (is_dir ($repo) && is_dir ("$repo/CVSROOT")) {
208 $repo_exists = true ;
212 system ("cvs -d $repo init") ;
213 system ("mkdir -p $locks_dir") ;
216 system ("chgrp -R $unix_group $repo $locks_dir") ;
217 system ("chmod 3777 $locks_dir") ;
218 if ($project->enableAnonSCM()) {
219 system ("chmod -R g+wXs,o+rX-w $repo") ;
221 system ("chmod -R g+wXs,o-rwx $repo") ;
225 function gatherStats ($params) {
226 $project = $this->checkParams ($params) ;
231 if (! $project->usesPlugin ($this->name)) {
235 if ($params['mode'] == 'day') {
238 $year = $params ['year'] ;
239 $month = $params ['month'] ;
240 $day = $params ['day'] ;
241 $month_string = sprintf( "%04d%02d", $year, $month );
242 $day_begin = gmmktime( 0, 0, 0, $month, $day, $year);
243 $day_end = $day_begin + 86400;
245 $repo = $this->cvs_root . '/' . $project->getUnixName() ;
246 if (!is_dir ($repo) || !is_dir ("$repo/CVSROOT")) {
247 echo "No repository\n" ;
255 $usr_commit = array();
258 $hist_file_path = $repo.'/CVSROOT/history';
259 if (!file_exists($hist_file_path)
260 || !is_readable($hist_file_path)
261 || filesize($hist_file_path) == 0) {
262 // echo "No history file\n" ;
267 $hist_file =& fopen( $hist_file_path, 'r' );
268 if ( ! $hist_file ) {
269 echo "Unreadable history\n" ;
274 // cleaning stats_cvs_* table for the current day
275 $res = db_query_params ('DELETE FROM stats_cvs_group WHERE month=$1 AND day=$2 AND group_id=$3',
276 array ($month_string,
278 $project->getID())) ;
280 echo "Error while cleaning stats_cvs_group\n" ;
285 $res = db_query_params ('DELETE FROM stats_cvs_user WHERE month=$1 AND day=$2 AND group_id=$3',
286 array ($month_string,
288 $project->getID())) ;
290 echo "Error while cleaning stats_cvs_user\n" ;
296 // analyzing history file
297 while (!feof($hist_file)) {
298 $hist_line = fgets($hist_file, 1024);
299 if ( preg_match( '/^\s*$/', $hist_line ) ) {
302 list( $cvstime,$user,$curdir,$module,$rev,$file ) = explode( '|', $hist_line );
304 $type = substr($cvstime, 0, 1);
305 $time_parsed = hexdec( substr($cvstime, 1, 8) );
307 if ( ($time_parsed > $day_begin) && ($time_parsed < $day_end) ) {
308 if ( $type == 'M' ) {
310 if(!isset($usr_commit[$user])) $usr_commit[$user] = 0;
311 $usr_commit[$user]++;
312 } elseif ( $type == 'A' ) {
314 if(!isset($usr_add[$user])) $usr_add[$user] = 0;
316 } elseif ( $type == 'O' || $type == 'E' ) {
318 // ignoring checkouts on a per-user
320 } elseif ( $time_parsed > $day_end ) {
324 fclose( $hist_file );
326 // inserting group results in stats_cvs_groups
327 if (!db_query_params ('INSERT INTO stats_cvs_group (month,day,group_id,checkouts,commits,adds) VALUES ($1,$2,$3,$4,$5,$6)',
328 array ($month_string,
334 echo "Error while inserting into stats_cvs_group\n" ;
339 // building the user list
340 $user_list = array_unique( array_merge( array_keys( $usr_add ), array_keys( $usr_commit ) ) );
342 foreach ( $user_list as $user ) {
343 // trying to get user id from user name
344 $u = &user_get_object_by_name ($last_user) ;
346 $user_id = $u->getID();
351 if (!db_query_params ('INSERT INTO stats_cvs_user (month,day,group_id,user_id,commits,adds) VALUES ($1,$2,$3,$4,$5,$6)',
352 array ($month_string,
356 $usr_commit[$user] ? $usr_commit[$user] : 0,
357 $usr_add[$user] ? $usr_add[$user] : 0))) {
358 echo "Error while inserting into stats_cvs_user\n" ;
367 function generateSnapshots ($params) {
371 $project = $this->checkParams ($params) ;
376 $group_name = $project->getUnixName() ;
378 $snapshot = forge_get_config('scm_snapshots_path').'/'.$group_name.'-scm-latest.tar.gz';
379 $tarball = forge_get_config('scm_tarballs_path').'/'.$group_name.'-scmroot.tar.gz';
381 if (! $project->usesPlugin ($this->name)) {
385 if (! $project->enableAnonSCM()) {
391 $toprepo = $this->cvs_root ;
392 $repo = $toprepo . '/' . $project->getUnixName() ;
394 $repo_exists = false ;
395 if (is_dir ($repo) && is_dir ("$repo/CVSROOT")) {
396 $repo_exists = true ;
405 $tmp = trim (`mktemp -d`) ;
409 $today = date ('Y-m-d') ;
410 $dir = $project->getUnixName ()."-$today" ;
411 system ("mkdir -p $tmp/$dir") ;
412 system ("cd $tmp/$dir ; cvs -d $repo checkout . > /dev/null 2>&1") ;
413 system ("tar czCf $tmp $tmp/snapshot.tar.gz $dir") ;
414 chmod ("$tmp/snapshot.tar.gz", 0644) ;
415 copy ("$tmp/snapshot.tar.gz", $snapshot) ;
416 unlink ("$tmp/snapshot.tar.gz") ;
417 system ("rm -rf $tmp/$dir") ;
419 system ("tar czCf $toprepo $tmp/tarball.tar.gz " . $project->getUnixName()) ;
420 chmod ("$tmp/tarball.tar.gz", 0644) ;
421 copy ("$tmp/tarball.tar.gz", $tarball) ;
422 unlink ("$tmp/tarball.tar.gz") ;
423 system ("rm -rf $tmp") ;
429 // c-file-style: "bsd"