SCMPlugin () ; $this->name = 'scmcvs'; $this->text = 'CVS'; $this->hooks[] = 'scm_browser_page'; $this->hooks[] = 'scm_generate_snapshots' ; $this->hooks[] = 'scm_gather_stats' ; $this->provides['cvs'] = true; $this->register () ; } function getDefaultServer() { return forge_get_config('default_server', 'scmcvs'); } function printShortStats ($params) { $project = $this->checkParams ($params) ; if (!$project) { return; } if ($project->usesPlugin($this->name) && forge_check_perm('scm', $project->getID(), 'read')) { $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; } if (!$add_num) { $add_num=0; } echo ' (CVS: '.sprintf(_('%1$s commits, %2$s adds'), number_format($commit_num, 0), number_format($add_num, 0)).")"; } } function getBlurb () { return '

' . sprintf(_('Documentation for %1$s is available at %2$s.'), 'CVS', 'http://cvsbook.red-bean.com/') . '

'; } function getInstructionsForAnon ($project) { $cvsrootend = $this->getBoxForProject($project).':'.forge_get_config('repos_path', 'scmcvs').'/'.$project->getUnixName(); $b = '

' . _('Anonymous CVS Access') . '

'; $b .= '

'; $b .= _('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 modulename. When prompted for a password for anonymous, simply press the Enter key.'); $b .= '

'; $b .= '

cvs -d :pserver:anonymous@' . $cvsrootend.' login
cvs -d :pserver:anonymous@' . $cvsrootend.' checkout '._('modulename').'

'; return $b ; } function getInstructionsForRW ($project) { $cvsrootend = $this->getBoxForProject($project).':'.forge_get_config('repos_path', 'scmcvs').'/'.$project->getUnixName(); if (session_loggedin()) { $u =& user_get_object(user_getid()) ; $d = $u->getUnixName() ; $b = '

'; $b .= sprintf(_('Developer %s Access via SSH'), 'CVS'); $b = '

'; $b .= '

'; $b .= sprintf(_('Only project developers can access the %s tree via this method.'), 'CVS'); $b .= ' '; $b .= _('SSH must be installed on your client machine.'); $b .= ' '; $b .= _('Substitute developername with the proper values.'); $b .= ' '; $b .= _('Enter your site password when prompted.'); $b .= '

'; $b .= '

export CVS_RSH=ssh
cvs -d :ext:'.$d.'@'.$cvsrootend.' checkout '._('modulename').'

'; } else { $b = '

'; $b .= sprintf(_('Developer %s Access via SSH'), 'CVS'); $b = '

'; $b .= '

'; $b .= sprintf(_('Only project developers can access the %s tree via this method.'), 'CVS'); $b .= ' '; $b .= _('SSH must be installed on your client machine.'); $b .= ' '; $b .= _('Substitute developername with the proper values.'); $b .= ' '; $b .= _('Enter your site password when prompted.'); $b .= '

'; $b .= '

export CVS_RSH=ssh
cvs -d :ext:'._('developername').'@'.$cvsrootend.' checkout '._('modulename').'

'; } return $b ; } function getSnapshotPara ($project) { $b = "" ; $filename = $project->getUnixName().'-scm-latest.tar'.util_get_compressed_file_extension(); if (file_exists(forge_get_config('scm_snapshots_path').'/'.$filename)) { $b .= '

[' ; $b .= util_make_link ("/snapshots.php?group_id=".$project->getID(), _('Download the nightly snapshot') ) ; $b .= ']

'; } return $b ; } function getBrowserLinkBlock ($project) { global $HTML ; $b = $HTML->boxMiddle(sprintf(_('%s Repository Browser'), 'CVS')); $b .= '

'; $b .= sprintf(_("Browsing the %s tree gives you a view into the current status of this project's code."), 'CVS'); $b .= ' '; $b .= _('You may also view the complete histories of any file in the repository.'); $b .= '

'; $b .= '

[' ; $b .= util_make_link ("/scm/browser.php?group_id=".$project->getID(), sprintf(_('Browse %s Repository'), 'CVS') ) ; $b .= ']

' ; return $b ; } function getStatsBlock ($project) { global $HTML ; $b = '' ; $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', array ($project->getID())); if (db_numrows($result) > 0) { $b .= $HTML->boxMiddle(_('Repository Statistics')); $tableHeaders = array( _('Name'), _('Adds'), _('Commits') ); $b .= $HTML->listTableTop($tableHeaders); $i = 0; $total = array('adds' => 0, 'commits' => 0); while($data = db_fetch_array($result)) { $b .= 'boxGetAltRowStyle($i) .'>'; $b .= '' ; $b .= util_make_link_u ($data['user_name'], $data['user_id'], $data['realname']) ; $b .= ''.$data['adds']. ''. ''.$data['commits'].''; $total['adds'] += $data['adds']; $total['commits'] += $data['commits']; $i++; } $b .= 'boxGetAltRowStyle($i) .'>'; $b .= ''._('Total').':'. ''.$total['adds']. ''. ''.$total['commits'].''; $b .= ''; $b .= $HTML->listTableBottom(); } return $b ; } function printBrowserPage ($params) { $project = $this->checkParams ($params) ; if (!$project) { return; } if ($project->usesPlugin ($this->name)) { if ($this->browserDisplayable ($project)) { session_redirect("/scm/viewvc.php/?root=".$project->getUnixName()); } } } function createOrUpdateRepo ($params) { $project = $this->checkParams ($params) ; if (!$project) { return false ; } if (! $project->usesPlugin ($this->name)) { return false; } $repo = forge_get_config('repos_path', 'scmcvs') . '/' . $project->getUnixName() ; $locks_dir = forge_get_config('repos_path', 'scmcvs') . '/cvs-locks/' . $project->getUnixName() ; $repo_exists = false ; if (is_dir ($repo) && is_dir ("$repo/CVSROOT")) { $repo_exists = true ; } if (forge_get_config('use_shell')) { $unix_group = 'scm_' . $project->getUnixName() ; } else { $unix_group = forge_get_config ('apache_user') ; } if (!$repo_exists) { if (!@mkdir($repo, 0700)) { return false; } $ret = 0; system ("cvs -d $repo init", $ret) ; if ($ret != 0) { return false; } system ("mkdir -p $locks_dir") ; system ("chgrp $unix_group $locks_dir") ; system ("chmod 3777 $locks_dir") ; if (forge_get_config('use_shell')) { util_create_file_with_contents ("$repo/CVSROOT/config", "SystemAuth=no\nLockDir=$locks_dir\nUseNewInfoFmtStrings=yes\n"); if ($project->enableAnonSCM()) { util_create_file_with_contents ("$repo/CVSROOT/readers", "anonymous\n"); util_create_file_with_contents ("$repo/CVSROOT/passwd", "anonymous:\n"); system ("chmod -R g+wXs,o+rX-w $repo") ; } else { util_create_file_with_contents ("$repo/CVSROOT/readers", "\n"); util_create_file_with_contents ("$repo/CVSROOT/passwd", "\n"); system ("chmod -R g+wXs,o-rwx $repo") ; } system ("chgrp -R $unix_group $repo") ; } else { $unix_user = forge_get_config ('apache_user') ; system ("chmod -R g-rwx,o-rwx $repo") ; system ("chown -R $unix_user:$unix_group $repo") ; } } if (forge_get_config('use_shell')) { if ($project->enableAnonSCM()) { util_create_file_with_contents ("$repo/CVSROOT/readers", "anonymous\n"); util_create_file_with_contents ("$repo/CVSROOT/passwd", "anonymous:\n"); system ("chmod g+wXs,o+rX-w $repo") ; } else { util_create_file_with_contents ("$repo/CVSROOT/readers", "\n"); util_create_file_with_contents ("$repo/CVSROOT/passwd", "\n"); system ("chmod g+wXs,o-rwx $repo") ; } } } 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 ); $day_begin = gmmktime( 0, 0, 0, $month, $day, $year); $day_end = $day_begin + 86400; $repo = forge_get_config('repos_path', 'scmcvs') . '/' . $project->getUnixName() ; if (!is_dir ($repo) || !is_dir ("$repo/CVSROOT")) { echo "No repository\n" ; db_rollback () ; return false ; } $cvs_co = 0; $cvs_commit = 0; $cvs_add = 0; $usr_commit = array(); $usr_add = array(); $hist_file_path = $repo.'/CVSROOT/history'; if (!file_exists($hist_file_path) || !is_readable($hist_file_path) || filesize($hist_file_path) == 0) { // echo "No history file\n" ; db_rollback () ; return false ; } $hist_file = fopen( $hist_file_path, 'r' ); if ( ! $hist_file ) { echo "Unreadable history\n" ; db_rollback () ; return false ; } // 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 file while (!feof($hist_file)) { $hist_line = fgets($hist_file, 1024); if ( preg_match( '/^\s*$/', $hist_line ) ) { continue; } list( $cvstime,$user,$curdir,$module,$rev,$file ) = explode( '|', $hist_line ); $type = substr($cvstime, 0, 1); $time_parsed = hexdec( substr($cvstime, 1, 8) ); if ( ($time_parsed > $day_begin) && ($time_parsed < $day_end) ) { if ( $type == 'M' ) { $cvs_commit++; if(!isset($usr_commit[$user])) $usr_commit[$user] = 0; $usr_commit[$user]++; } elseif ( $type == 'A' ) { $cvs_add++; if(!isset($usr_add[$user])) $usr_add[$user] = 0; $usr_add[$user]++; } elseif ( $type == 'O' || $type == 'E' ) { $cvs_co++; // ignoring checkouts on a per-user } } elseif ( $time_parsed > $day_end ) { break; } } fclose( $hist_file ); // inserting group results in stats_cvs_groups 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(), $cvs_co, $cvs_commit, $cvs_add))) { 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_add ), array_keys( $usr_commit ) ) ); 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; } 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, isset ($usr_commit[$user]) ? $usr_commit[$user] : 0, isset ($usr_add[$user]) ? $usr_add[$user] : 0))) { echo "Error while inserting into stats_cvs_user\n" ; db_rollback () ; return false ; } } } db_commit(); } function generateSnapshots ($params) { $project = $this->checkParams ($params) ; if (!$project) { return false ; } $group_name = $project->getUnixName() ; $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 (file_exists($snapshot)) unlink ($snapshot) ; if (file_exists($tarball)) unlink ($tarball) ; return false; } $toprepo = forge_get_config('repos_path', 'scmcvs') ; $repo = $toprepo . '/' . $project->getUnixName() ; $repo_exists = false ; if (is_dir ($repo) && is_dir ("$repo/CVSROOT")) { $repo_exists = true ; } if (!$repo_exists) { if (file_exists($snapshot)) unlink ($snapshot) ; if (file_exists($tarball)) unlink ($tarball) ; return false ; } $tmp = trim (`mktemp -d`) ; if ($tmp == '') { return false ; } $today = date ('Y-m-d') ; $dir = $project->getUnixName ()."-$today" ; system ("mkdir -p $tmp/$dir") ; system ("cd $tmp/$dir ; cvs -d $repo export -D now . > /dev/null 2>&1") ; system ("tar cCf $tmp - $dir |".forge_get_config('compression_method')."> $tmp/snapshot") ; chmod ("$tmp/snapshot", 0644) ; copy ("$tmp/snapshot", $snapshot) ; unlink ("$tmp/snapshot") ; system ("rm -rf $tmp/$dir") ; system ("tar cCf $toprepo - ".$project->getUnixName() ."|".forge_get_config('compression_method')."> $tmp/tarball") ; chmod ("$tmp/tarball", 0644) ; copy ("$tmp/tarball", $tarball) ; unlink ("$tmp/tarball") ; system ("rm -rf $tmp") ; } } // Local Variables: // mode: php // c-file-style: "bsd" // End: