2 /** FusionForge Git plugin
4 * Copyright 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 GitPlugin extends SCMPlugin {
25 function GitPlugin () {
28 $this->name = 'scmgit';
30 $this->hooks[] = 'scm_update_repolist' ;
31 $this->hooks[] = 'scm_browser_page' ;
32 $this->hooks[] = 'scm_gather_stats' ;
33 $this->hooks[] = 'scm_generate_snapshots' ;
35 require_once $gfconfig.'plugins/scmgit/config.php' ;
37 $this->default_git_server = $default_git_server ;
38 if (isset ($git_root)) {
39 $this->git_root = $git_root;
41 $this->git_root = $GLOBALS['sys_chroot'].'/scmrepos/git' ;
47 function getDefaultServer() {
48 return $this->default_git_server ;
51 function getBlurb () {
52 return _('<p>This GIT plugin is not completed yet.</p>') ;
55 function getInstructionsForAnon ($project) {
56 $b = _('<p><b>Anonymous Git Access</b></p><p>This project\'s Git repository can be checked out through anonymous access with the following command.</p>');
58 $b .= '<tt>git clone '.util_make_url ('/anonscm/git/'.$project->getUnixName().'/').'</tt><br />';
63 function getInstructionsForRW ($project) {
64 $b = _('<p><b>Developer GIT Access via SSH</b></p><p>Only project developers can access the GIT 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>');
65 $b .= '<p><tt>git clone git+ssh://<i>'._('developername').'</i>@' . $project->getSCMBox() . ':'. $this->git_root .'/'. $project->getUnixName().'</tt></p>' ;
69 function getSnapshotPara ($project) {
70 global $sys_scm_snapshots_path ;
72 $filename = $project->getUnixName().'-scm-latest.tar.gz';
73 if (file_exists($sys_scm_snapshots_path.'/'.$filename)) {
75 $b .= util_make_link ("/snapshots.php?group_id=".$project->getID(),
76 _('Download the nightly snapshot')
83 function printBrowserPage ($params) {
86 $project = $this->checkParams ($params) ;
91 if ($project->usesPlugin ($this->name)) {
92 if ($this->browserDisplayable ($project)) {
93 print '<iframe src="'.util_make_url ("/plugins/scmgit/cgi-bin/gitweb.cgi?p=".$project->getUnixName()).'" frameborder="no" width=100% height=700></iframe>' ;
98 function getBrowserLinkBlock ($project) {
100 $b = $HTML->boxMiddle(_('Git Repository Browser'));
101 $b .= _('<p>Browsing the Git 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>');
103 $b .= util_make_link ("/scm/browser.php?group_id=".$project->getID(),
104 _('Browse Git Repository')
110 // function getStatsBlock ($project) {
114 // $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',
115 // array ($project->getID()));
117 // if (db_numrows($result) > 0) {
118 // $b .= $HTML->boxMiddle(_('Repository Statistics'));
120 // $tableHeaders = array(
125 // $b .= $HTML->listTableTop($tableHeaders);
128 // $total = array('adds' => 0, 'commits' => 0);
130 // while($data = db_fetch_array($result)) {
131 // $b .= '<tr '. $HTML->boxGetAltRowStyle($i) .'>';
132 // $b .= '<td width="50%">' ;
133 // $b .= util_make_link_u ($data['user_name'], $data['user_id'], $data['realname']) ;
134 // $b .= '</td><td width="25%" align="right">'.$data['adds']. '</td>'.
135 // '<td width="25%" align="right">'.$data['commits'].'</td></tr>';
136 // $total['adds'] += $data['adds'];
137 // $total['commits'] += $data['commits'];
140 // $b .= '<tr '. $HTML->boxGetAltRowStyle($i) .'>';
141 // $b .= '<td width="50%"><strong>'._('Total').':</strong></td>'.
142 // '<td width="25%" align="right"><strong>'.$total['adds']. '</strong></td>'.
143 // '<td width="25%" align="right"><strong>'.$total['commits'].'</strong></td>';
145 // $b .= $HTML->listTableBottom();
146 // $b .= '<hr size="1" />';
151 function getStatsBlock ($project) {
155 function createOrUpdateRepo ($params) {
156 $project = $this->checkParams ($params) ;
161 if (! $project->usesPlugin ($this->name)) {
165 $project_name = $project->getUnixName() ;
166 $repo = $this->git_root . '/' . $project_name ;
167 $unix_group = 'scm_' . $project_name ;
169 system ("mkdir -p $repo") ;
170 if (!is_file ("$repo/HEAD") && !is_dir("$repo/objects") && !is_dir("$repo/refs")) {
171 system ("GIT_DIR=\"$repo\" git --bare init") ;
172 system ("echo \"Git repository for $project_name\" > $repo/description") ;
175 system ("chgrp -R $unix_group $repo") ;
176 if ($project->enableAnonSCM()) {
177 system ("chmod -R g+wXs,o+rX-w $repo") ;
179 system ("chmod -R g+wXs,o-rwx $repo") ;
183 function updateRepositoryList ($params) {
184 $groups = $this->getGroups () ;
186 foreach ($groups as $project) {
187 if ($this->browserDisplayable ($project)) {
192 $config_dir = '/etc/gforge/plugins/scmgit' ;
193 $fname = $config_dir . '/gitweb.conf' ;
194 $config_f = fopen ($fname.'.new', 'w') ;
195 $rootdir = $this->git_root;
196 fwrite($config_f, "\$projectroot = '$rootdir';\n");
197 fwrite($config_f, "\$projects_list = '$config_dir/gitweb.list';\n");
198 fwrite($config_f, "@git_base_url_list = ('". util_make_url ('/anonscm/git/') . "');\n");
199 fwrite($config_f, "\$logo = '". util_make_url ('/plugins/scmgit/gitweb/git-logo.png') . "';\n");
200 fwrite($config_f, "\$favicon = '". util_make_url ('/plugins/scmgit/gitweb/git-favicon.png')."';\n");
201 fwrite($config_f, "\$stylesheet = '". util_make_url ('/plugins/scmgit/gitweb/gitweb.css')."';\n");
202 fwrite($config_f, "\$prevent_xss = 'true';\n");
204 chmod ($fname.'.new', 0644) ;
205 rename ($fname.'.new', $fname) ;
207 $fname = $config_dir . '/gitweb.list' ;
209 $f = fopen ($fname.'.new', 'w') ;
210 foreach ($list as $project) {
211 fwrite ($f, $project->getUnixName() . "\n");
214 chmod ($fname.'.new', 0644) ;
215 rename ($fname.'.new', $fname) ;
218 function generateSnapshots ($params) {
219 global $sys_scm_tarballs_path ;
221 $project = $this->checkParams ($params) ;
226 $group_name = $project->getUnixName() ;
228 $snapshot = $sys_scm_snapshots_path.'/'.$group_name.'-scm-latest.tar.gz';
229 $tarball = $sys_scm_tarballs_path.'/'.$group_name.'-scmroot.tar.gz';
231 if (! $project->usesPlugin ($this->name)) {
235 if (! $project->enableAnonSCM()) {
240 $toprepo = $this->git_root ;
241 $repo = $toprepo . '/' . $project->getUnixName() ;
243 if (!is_dir ($repo)) {
248 $today = date ('Y-m-d') ;
249 $tmp = trim (`mktemp -d`) ;
254 system ("git archive --format=tar --prefix=$group_name-scm-$today/ HEAD | gzip > $tmp/snapshot.tar.gz");
255 chmod ("$tmp/snapshot.tar.gz", 0644) ;
256 copy ("$tmp/snapshot.tar.gz", $snapshot) ;
257 unlink ("$tmp/snapshot.tar.gz") ;
259 system ("tar czCf $toprepo $tmp/tarball.tar.gz " . $project->getUnixName()) ;
260 chmod ("$tmp/tarball.tar.gz", 0644) ;
261 copy ("$tmp/tarball.tar.gz", $tarball) ;
262 unlink ("$tmp/tarball.tar.gz") ;
263 system ("rm -rf $tmp") ;
266 function gatherStats ($params) {
267 global $last_user, $usr_adds, $usr_deletes,
268 $usr_updates, $updates, $adds;
270 $project = $this->checkParams ($params) ;
275 if (! $project->usesPlugin ($this->name)) {
279 if ($params['mode'] == 'day') {
282 $year = $params ['year'] ;
283 $month = $params ['month'] ;
284 $day = $params ['day'] ;
285 $month_string = sprintf( "%04d%02d", $year, $month );
286 $start_time = gmmktime( 0, 0, 0, $month, $day, $year);
287 $end_time = $start_time + 86400;
289 $usr_adds = array () ;
290 $usr_updates = array () ;
291 $usr_deletes = array () ;
296 $repo = $this->git_root . '/' . $project->getUnixName() ;
297 if (!is_dir ($repo) || !is_file ("$repo/refs")) {
298 // echo "No repository\n" ;
303 $pipe = popen ("GIT_DIR=$repo git log --since='1 day ago' "
304 ."--all --pretty='%n%an <%ae>' --name-status", 'r' ) ;
306 // cleaning stats_cvs_* table for the current day
307 $res = db_query_params ('DELETE FROM stats_cvs_group WHERE month=$1 AND day=$2 AND group_id=$3',
308 array ($month_string,
310 $project->getID())) ;
312 echo "Error while cleaning stats_cvs_group\n" ;
318 while (!feof($pipe) && $data = fgets ($pipe)) {
320 if (strlen($line) > 0) {
321 $result = preg_match("/^(?<name>.+) <(?<mail>.+)>/", $line, $matches);
324 $last_user = $matches['name'];
326 // Short-commit stats line
327 preg_match("/(?<mode>[AM])[ ]+(?<file>.+)$/", $line, $matches);
328 if ($last_user == "") continue;
329 if ($matches['mode'] == 'A') {
330 $usr_adds[$last_user]++;
332 } elseif ($matches['mode'] == 'M') {
333 $usr_updates[$last_user]++;
335 } elseif ($matches['mode'] == 'D') {
336 $usr_deletes[$last_user]++;
342 // inserting group results in stats_cvs_groups
343 if (!db_query_params ('INSERT INTO stats_cvs_group (month,day,group_id,checkouts,commits,adds) VALUES ($1,$2,$3,$4,$5,$6)',
344 array ($month_string,
350 echo "Error while inserting into stats_cvs_group\n" ;
355 // building the user list
356 $user_list = array_unique( array_merge( array_keys( $usr_adds ), array_keys( $usr_updates ) ) );
358 foreach ( $user_list as $user ) {
359 // trying to get user id from user name
360 $u = &user_get_object_by_name ($user) ;
362 $user_id = $u->getID();
367 if (!db_query_params ('INSERT INTO stats_cvs_user (month,day,group_id,user_id,commits,adds) VALUES ($1,$2,$3,$4,$5,$6)',
368 array ($month_string,
372 $usr_updates[$user] ? $usr_updates[$user] : 0,
373 $usr_adds[$user] ? $usr_adds[$user] : 0))) {
374 echo "Error while inserting into stats_cvs_user\n" ;
386 // c-file-style: "bsd"