add modified files
authorStricted <Stricted@nexus-irc.de>
Fri, 7 Sep 2012 18:39:25 +0000 (20:39 +0200)
committerStricted <Stricted@nexus-irc.de>
Fri, 7 Sep 2012 18:39:25 +0000 (20:39 +0200)
17 files changed:
git_bugtrack.php [new file with mode: 0644]
git_download.php [new file with mode: 0644]
git_graph.php [new file with mode: 0644]
git_version.php [new file with mode: 0644]
gitweb.css [new file with mode: 0644]
images/branch_left.png [new file with mode: 0644]
images/branch_right.png [new file with mode: 0644]
images/dot.png [new file with mode: 0644]
images/dot_init.png [new file with mode: 0644]
images/dot_merge.png [new file with mode: 0644]
images/dot_merge_left.png [new file with mode: 0644]
images/dot_merge_right.png [new file with mode: 0644]
images/line.png [new file with mode: 0644]
images/line_h.png [new file with mode: 0644]
images/merge_left.png [new file with mode: 0644]
images/merge_right.png [new file with mode: 0644]
index.cgi

diff --git a/git_bugtrack.php b/git_bugtrack.php
new file mode 100644 (file)
index 0000000..9cd226a
--- /dev/null
@@ -0,0 +1,12 @@
+<p><?php
+if($_GET["p"]){
+       $hash = shell_exec("git --git-dir=/home/git/".$_GET["p"]." rev-list -n 1 --pretty='format:%h' --header master | grep '^[0-9a-f]*$'");
+       if(!$hash){
+               echo "<b>unknown project or no bugtracker for this project</b>";
+       }else{
+               echo "<b>under construction</b>";
+       }
+}else{
+       echo "<b>unknown project or no bugtracker for this project</b";
+}
+?></p>
\ No newline at end of file
diff --git a/git_download.php b/git_download.php
new file mode 100644 (file)
index 0000000..df0852b
--- /dev/null
@@ -0,0 +1,71 @@
+<?php
+if(isset($_GET['p'])){
+       if(file_exists("/home/git/".$_GET['p'])){
+               $hash = shell_exec("git --git-dir=/home/git/".$_GET["p"]." rev-list -n 1 --pretty='format:%h' --header master | grep '^[0-9a-f]*$'");
+               $con= shell_exec('git --git-dir=/home/git/'.$_GET["p"].' rev-list --oneline --header master | wc -l | sed "s/[ \t]//g"');
+               if(!$hash){
+                       echo "<p>".$_GET["p"].": No Download available</p>";
+               }else{
+                       $name=substr($_GET["p"],0,strlen($_GET["p"])-4);  
+                       if(file_exists("/usr/share/gitweb/dl/".$name."-git-".substr($con, 0, -1)."-".substr($hash, 0, -1).".tar.gz")) {
+                               echo "<p>".$_GET["p"].": Download <a href='http://git.nexus-irc.de/dl/".$name."-git-".substr($con, 0, -1)."-".substr($hash, 0, -1).".tar.gz'>git-".substr($con, 0, -1)."-".substr($hash, 0, -1)."</a></p>";
+                       } else {
+                               echo "<p>".$_GET["p"].": No Download available (<a href='http://git.nexus-irc.de/git_download.php?build2=".$_GET["p"]."'>Build snapshot</a>)</p>";
+                       }
+               }
+       }else{
+               echo "unknown project";
+       }
+}elseif(isset($_GET['build'])){
+       if(file_exists("/home/git/".$_GET['build'])){
+               $name=substr($_GET['build'],0,strlen($_GET['build'])-4);
+               if(file_exists("/usr/share/gitweb/dl/".$name."-git-".substr($con, 0, -1)."-".substr($hash, 0, -1).".tar.gz")) {
+                       echo '<meta http-equiv="refresh" content="0; URL=http://git.nexus-irc.de/?a=downloads"> ';
+               }else{
+                       $hash = shell_exec("git --git-dir=/home/git/".$_GET['build']." rev-list -n 1 --pretty='format:%h' --header master | grep '^[0-9a-f]*$'");
+                       $con= shell_exec('git --git-dir=/home/git/'.$_GET['build'].' rev-list --oneline --header master | wc -l | sed "s/[ \t]//g"');
+                       $b = shell_exec("cd /usr/share/gitweb/dl; git clone git://git.nexus-irc.de/".$_GET['build']);
+                       $c = shell_exec("cd /usr/share/gitweb/dl; tar czfv ".$name."-git-".substr($con, 0, -1)."-".substr($hash, 0, -1).".tar.gz ".$name);
+                       $d = shell_exec("rm -r /usr/share/gitweb/dl/".$name);
+                       echo '<meta http-equiv="refresh" content="0; URL=http://git.nexus-irc.de/?a=downloads"> ';
+               }
+       }else{
+               echo "unknown project";
+       }
+}elseif(isset($_GET['build2'])){
+       if(file_exists("/home/git/".$_GET['build2'])){
+               $name=substr($_GET['build2'],0,strlen($_GET['build2'])-4);
+               if(file_exists("/usr/share/gitweb/dl/".$name."-git-".substr($con, 0, -1)."-".substr($hash, 0, -1).".tar.gz")) {
+                       echo '<meta http-equiv="refresh" content="0; URL=http://git.nexus-irc.de/?p='.$_GET['build2'].';a=download"> ';
+               }else{
+               $hash = shell_exec("git --git-dir=/home/git/".$_GET['build2']." rev-list -n 1 --pretty='format:%h' --header master | grep '^[0-9a-f]*$'");
+               $con= shell_exec('git --git-dir=/home/git/'.$_GET['build2'].' rev-list --oneline --header master | wc -l | sed "s/[ \t]//g"');
+               $b = shell_exec("cd /usr/share/gitweb/dl/; git clone git://git.nexus-irc.de/".$_GET['build2']);
+               $c = shell_exec("cd /usr/share/gitweb/dl; tar czfv ".$name."-git-".substr($con, 0, -1)."-".substr($hash, 0, -1).".tar.gz ".$name);
+               $d = shell_exec("rm -r /usr/share/gitweb/dl/".$name);
+               echo '<meta http-equiv="refresh" content="0; URL=http://git.nexus-irc.de/?p='.$_GET['build2'].';a=download"> ';
+               }
+       }else{
+               echo "unknown project";
+       }
+}else{
+       $a = file_get_contents("http://git.nexus-irc.de/index.cgi?a=project_index2");
+       $b = explode("\n",$a);
+       foreach($b as $id => $v) {
+               if($v == ""){ }else{
+                       $hash = shell_exec("git --git-dir=/home/git/".$v." rev-list -n 1 --pretty='format:%h' --header master | grep '^[0-9a-f]*$'");
+                       $con= shell_exec('git --git-dir=/home/git/'.$v.' rev-list --oneline --header master | wc -l | sed "s/[ \t]//g"');
+                       if(!$hash){
+                               echo "<p>".$v.": No Download available</p>";
+                       }else{
+                               $name=substr($v,0,strlen($v)-4);
+                               if(file_exists("/usr/share/gitweb/dl/".$name."-git-".substr($con, 0, -1)."-".substr($hash, 0, -1).".tar.gz")) {
+                                       echo "<p>".$v.": Download <a href='http://git.nexus-irc.de/dl/".$name."-git-".substr($con, 0, -1)."-".substr($hash, 0, -1).".tar.gz'>git-".substr($con, 0, -1)."-".substr($hash, 0, -1)."</a></p>";
+                               } else {
+                                       echo "<p>".$v.": No Download available (<a href='http://git.nexus-irc.de/git_download.php?build=".$v."'>Build snapshot</a>)</p>";       
+                               }
+                       }
+               }
+       }
+}
+?>
\ No newline at end of file
diff --git a/git_graph.php b/git_graph.php
new file mode 100644 (file)
index 0000000..a25bc8d
--- /dev/null
@@ -0,0 +1,405 @@
+<?php
+
+/* CONFIG */
+$repo_path = "/home/git/";
+$project_list = null;
+
+$size = 20;
+$tile_size = 20; /* do not edit */
+
+$max_branches = 30;
+$use_local_branches = true;
+$use_remote_branches = true;
+
+$colors = array(
+    NULL,
+    array(255, 0, 0),
+    array(0, 255, 0),
+    array(0, 0, 255),
+    array(128, 128, 128),
+    array(128, 128, 0),
+    array(0, 128, 128),
+    array(128, 0, 128)
+);
+/* END CONFIG */
+
+session_start();
+
+//parse ; seprated query args
+$args = explode(";", $_SERVER["QUERY_STRING"]);
+foreach($args as $arg) {
+    $arg = explode("=", $arg, 2);
+    $_GET[$arg[0]] = $arg[1];
+}
+
+if($_SESSION['gitgraph_maxbranch'])
+    $max_branches = $_SESSION['gitgraph_maxbranch'];
+if($_GET['maxbranch']) {
+    $_SESSION['gitgraph_maxbranch'] = $_GET['maxbranch'];
+    die("maxbranch set.");
+}
+
+//check if project is in $project_list
+$project = NULL;
+if($project_list) {
+    $projects = file_get_contents($project_list);
+    foreach(explode("\n", $projects) as $cproject) {
+        $cproject = explode(" ", $cproject);
+        if(strtolower($_GET['p']) == strtolower($cproject[0])) {
+            if(file_exists($repo_path.$cproject[0]))
+                $project = $cproject[0];
+            break;
+        }
+    }
+} else {
+    if(!preg_match('#^[a-z0-9.-_]*$#i', $_GET['p']))
+        die("ERROR 0x01");
+    if(file_exists($repo_path.$_GET['p']))
+        $project = $_GET['p'];
+}
+if(!$project)
+    die("ERROR 0x02");
+
+//check other args
+if(!preg_match('#^[a-z0-9/.-_]*$#i', $_GET['h']))
+    die("ERROR 0x03");
+if(!preg_match('#^[a-z0-9]*$#i', $_GET['c']))
+    die("ERROR 0x04");
+if(!preg_match('#^[0-9]*$#i', $_GET['from']))
+    die("ERROR 0x05");
+if(!preg_match('#^[0-9]*$#i', $_GET['to']))
+    die("ERROR 0x06");
+
+//load old cache
+$data = array();
+if($_SESSION['git_graph']) {
+    $old_data = unserialize($_SESSION['git_graph']);
+    if($old_data['r'] == $_GET['r'])
+        $data = $old_data;
+}
+
+function parse_commit($commit_data) {
+    $commit = array();
+    $rev_lines = explode("\n", str_replace("\r", "", $commit_data));
+    $commit['id'] = $rev_lines[0];
+    foreach($rev_lines as $rev_line) {
+        if(substr($rev_line, 0, 4) == "    ") {
+            if($commit['text'])
+                $commit['text'] .= "\n";
+            $commit['text'] .= substr($rev_line, 4);
+        } else {
+            $opt = explode(" ", $rev_line);
+            if($opt[0] == "tree")
+                $commit['tree'] = $opt[1];
+            else if($opt[0] == "parent")
+                $commit['parent'][] = $opt[1];
+            else if($opt[0] == "author") {
+                $commit['author'] = $opt[1];
+                $commit['author_mail'] = $opt[2];
+                $commit['author_time'] = $opt[3];
+            } else if($opt[0] == "committer") {
+                $commit['committer'] = $opt[1];
+                $commit['committer_mail'] = $opt[2];
+                $commit['committer_time'] = $opt[3];
+            }
+        }
+    }
+    return $commit;
+}
+
+//load rev-list
+if(!$data['commits']) {
+    $cmd = "git --git-dir=".$repo_path.$project." rev-list --header --max-count=".($_GET['to'] + 1)." ".($_GET['h'] =="all" ? "--all" : $_GET['h']);
+    $rev_list = shell_exec($cmd);
+    foreach(explode("\000", $rev_list) as $rev) {
+        $data['commits'][] = parse_commit($rev);
+    }
+}
+
+//save cache
+$_SESSION['git_graph'] = serialize($data);
+
+//generate graph data
+$data['branches'] = array();
+$data['ubranches'] = array();
+$brach_id = 1;
+$brach_uid = 1;
+$graph_commit = NULL;
+$first_commit = true;
+
+if($_GET['h'] == "all") {
+    //set master branch as first branch
+    $cmd = "git --git-dir=".$repo_path.$project." rev-list --header --max-count=1 HEAD";
+    $head_list = shell_exec($cmd);
+    $head = parse_commit($head_list);
+    $first_commit = false;
+    $data['branches'][count($data['branches'])] = array();
+    $branch = &$data['branches'][count($data['branches'])-1];
+    $branch['id'] = $brach_id++;
+    $branch['uid'] = $branch_uid++;
+    $branch['active'] = true;
+    $branch['next'] = $head['id'];
+    unset($branch);
+    if($use_local_branches) {
+        $cmd = "git --git-dir=".$repo_path.$project." for-each-ref --sort=-committerdate refs/heads/";
+        $head_list = shell_exec($cmd);
+        foreach(explode("\n", str_replace("\r", "", $head_list)) as $head) {
+            $head = explode(" ", $head);
+            if(!$head[0])
+                continue;
+            $existing = false;
+            foreach($data['branches'] as $branch) {
+                if($branch['next'] == $head[0]) {
+                    $existing = true;
+                    break;
+                }
+            }
+            if($existing)
+                continue;
+            $data['branches'][count($data['branches'])] = array(
+                "id" => $brach_id++,
+                "uid" => $brach_uid++,
+                "active" => true,
+                "next" => $head[0]
+            );
+        }
+    }
+    if($use_remote_branches) {
+        $cmd = "git --git-dir=".$repo_path.$project." for-each-ref --sort=-committerdate refs/remotes/";
+        $head_list = shell_exec($cmd);
+        foreach(explode("\n", str_replace("\r", "", $head_list)) as $head) {
+            $head = explode(" ", $head);
+            if(!$head[0])
+                continue;
+            $existing = false;
+            foreach($data['branches'] as $branch) {
+                if($branch['next'] == $head[0]) {
+                    $existing = true;
+                    break;
+                }
+            }
+            if($existing)
+                continue;
+            $data['branches'][count($data['branches'])] = array(
+                "id" => $brach_id++,
+                "uid" => $brach_uid++,
+                "active" => true,
+                "next" => $head[0]
+            );
+        }
+    }
+}
+
+for($i = 0; $i <= intval($_GET['to']); $i++) {
+//for($i = 0; $i < count($data['commits']); $i++) {
+    $commit = &$data['commits'][$i];
+    //get current branch
+    if($first_commit) {
+        $first_commit = false;
+        $data['branches'][0] = array();
+        $branch = &$data['branches'][0];
+        $branch['id'] = $brach_id++;
+        $branch['uid'] = $branch_uid++;
+        $branch['active'] = true;
+    } else {
+        $first = true;
+        foreach($data['branches'] as $id => &$cbranch) {
+            if($cbranch['next'] == $commit['id']) {
+                if($first && !$cbranch['pre_merge']) {
+                    $branch = &$data['branches'][$id];
+                    $first = false;
+                }
+            }
+        }
+        foreach($data['branches'] as $id => &$cbranch) {
+            if($cbranch['next'] == $commit['id']) {
+                if($first) {
+                    $branch = &$data['branches'][$id];
+                    $first = false;
+                } else if($cbranch['id'] == $branch['id']) {
+                } else {
+                    $commit['merge'][] = array("point" => $cbranch['id'], "start" => true);
+                    $cbranch['active'] = false;
+                    if($cbranch['pre_merge']) {
+                        $cbranch['pre_merge_start'] = true;
+                        $cbranch['pre_merge_id'] = $branch['id'];
+                        $data['ubranches'][$cbranch['uid']] = $data['branches'][$cbranch['id']-1];
+                    }
+                }
+            }
+        }
+        unset($cbranch);
+        if($first) {
+            $data['branches'][count($data['branches'])] = array();
+            $branch = &$data['branches'][count($data['branches'])-1];
+            $branch['id'] = $brach_id++;
+            $branch['uid'] = $branch_uid++;
+            $branch['active'] = true;
+        }
+    }
+    
+    if(count($commit['parent']) > 1) {
+        //merge(s)
+        for($j = 1; $j < count($commit['parent']); $j++) {
+            $add = true;
+            foreach($data['branches'] as $cbranch) {
+                if($cbranch['next'] == $commit['parent'][$j]) {
+                    $add = false;
+                    break;
+                }
+            }
+            if($add) {
+                $cadd = true;
+                foreach($data['branches'] as $bid => &$cbranch) {
+                    if(!$cbranch['active']) {
+                        $cadd = false;
+                        break;
+                    }
+                }
+                if($cadd) {
+                    $data['branches'][count($data['branches'])] = array();
+                    $cbranch = &$data['branches'][count($data['branches'])-1];
+                    $cbranch['id'] = $brach_id++;
+                }
+                $cbranch['uid'] = $branch_uid++;
+                $cbranch['active'] = true;
+                $cbranch['pre_merge'] = true;
+                $cbranch['next'] = $commit['parent'][$j];
+            }
+            $commit['merge'][] = array("point" => $cbranch['id'], "end" => $add);
+            $commit['dot_merge'] = true;
+            $data['ubranches'][$cbranch['uid']] = $data['branches'][$cbranch['id']-1];
+            unset($cbranch);
+        }
+    } else if(count($commit['parent']) == 0) {
+        $branch['active'] = false;
+        $commit['dot_init'] = true;
+    }
+    $branch['next'] = $commit['parent'][0];
+    $branch['pre_merge'] = false;
+    $data['ubranches'][$branch['uid']] = $data['branches'][$branch['id']-1];
+    
+    $commit['dot'] = $branch['id'];
+    
+    foreach($data['branches'] as $id => $cbranch) {
+        $commit['branches'][$id] = $cbranch;
+    }
+    
+    if($commit['id'] == $_GET['c']) {
+        //yeaaa  i've found a PHP Bug :D
+        //$graph_commit['branches'] still gets updated.. (damn references)
+        //we need a fully independent copy of the array....
+        $graph_commit = $commit;
+    }
+}
+
+if($graph_commit == NULL)
+    die("ERROR 0x07");
+
+//DEV Breakpoint
+//print_r($data);
+//die();
+
+//generate image
+$count = count($data['branches']);
+if($count > $max_branches)
+    $count = $max_branches;
+$image = imagecreatetruecolor($count * $size, $size);
+$transparentIndex = imagecolorallocate($image, 0xFF, 0xFF, 0xFF);
+imagefill($image, 0, 0, $transparentIndex);
+
+function image_set_color($src, $color) {
+    global $size;
+    imagesavealpha($src, true);
+    imagealphablending($src, false);
+    // scan image pixels
+    for ($x = 0; $x < $size; $x++) {
+        for ($y = 0; $y < $size; $y++) {
+            $src_pix = imagecolorat($src,$x,$y);
+            $src_pix_array = imagecolorsforindex($src, $src_pix);
+            
+            imagesetpixel($src, $x, $y, imagecolorallocatealpha($src, $color[0], $color[1], $color[2], $src_pix_array['alpha']));
+        }
+    }
+}
+
+function overlay_image($name, $left, $color = false) {
+    global $image, $size, $tile_size;
+    $image2 = imagecreatefrompng($name);
+
+    if($color) {
+        image_set_color($image2, $color);
+    }
+    imagecopyresampled($image, $image2, $left, 0, 0, 0, $size, $size, $tile_size, $tile_size);
+}
+
+function get_color($id) {
+    global $colors, $graph_commit, $data;
+    if($graph_commit['branches'][($id-1)]['pre_merge']) {
+        $branch = $data['ubranches'][$graph_commit['branches'][($id-1)]['uid']];
+        if($branch['pre_merge'] && $branch['pre_merge_start'])
+            $id = $branch['pre_merge_id'];
+    }
+    return $colors[($id - 1) % count($colors)];
+}
+
+foreach($graph_commit['branches'] as $branch) {
+    $left = ($branch['id']-1) * $size;
+    if($branch['active']) {
+        if($graph_commit['dot'] == $branch['id']) continue;
+        $show = true;
+        if($graph_commit['merge']) {
+            foreach($graph_commit['merge'] as $merge) {
+                if($merge['point'] == $branch['id']) {
+                    $show = false;
+                    break;
+                }
+            }
+        }
+        if(!$show) continue;
+        if($branch['id'] > $max_branches) continue;
+        overlay_image("images/line.png", $left, get_color($branch['id']));
+    }
+}
+
+if($graph_commit['merge']) {
+    foreach($graph_commit['merge'] as $merge) {
+        $dot_dir = ($graph_commit['dot'] < $merge['point'] ? "right" : "left");
+        $merge_dir = ($graph_commit['dot'] < $merge['point'] ? "left" : "right");
+        
+        if($graph_commit['dot'] <= $max_branches)
+            overlay_image("images/dot_merge_".$dot_dir.".png", ($graph_commit['dot'] - 1) * $size, get_color($merge['point']));
+        
+        if($merge['point'] <= $max_branches) {
+            overlay_image("images/".($merge['start'] ? "branch" : "merge")."_".$merge_dir.".png", ($merge['point'] - 1) * $size, get_color($merge['point']));
+            if(!$merge['start'] && !$merge['end'])
+                overlay_image("images/line.png", ($merge['point'] - 1) * $size, get_color($merge['point']));
+        }
+        $min = ($graph_commit['dot'] < $merge['point'] ? $graph_commit['dot'] : $merge['point']) + 1;
+        $max = ($graph_commit['dot'] < $merge['point'] ? $merge['point'] : $graph_commit['dot']);
+        for($i = $min; $i < $max; $i++) {
+            if($i > $max_branches) continue;
+            overlay_image("images/line_h.png", ($i - 1) * $size, get_color($merge['point']));
+        }
+    }
+    if($graph_commit['dot'] <= $max_branches) {
+        if($graph_commit['dot_merge'])
+            overlay_image("images/dot_merge.png", ($graph_commit['dot'] - 1) * $size, get_color($graph_commit['dot']));
+        else
+            overlay_image("images/dot.png", ($graph_commit['dot'] - 1) * $size, get_color($graph_commit['dot']));
+    }
+} else if($graph_commit['dot_init']) {
+    if($graph_commit['dot'] <= $max_branches)
+        overlay_image("images/dot_init.png", ($graph_commit['dot'] - 1) * $size, get_color($graph_commit['dot']));
+} else if($graph_commit['dot']) {
+    if($graph_commit['dot'] <= $max_branches)
+        overlay_image("images/dot.png", ($graph_commit['dot'] - 1) * $size, get_color($graph_commit['dot']));
+}
+
+imagecolortransparent($image, $transparentIndex);
+
+header('Content-Type: image/png');
+imagepng($image);
+imagedestroy($image);
+
+?>
\ No newline at end of file
diff --git a/git_version.php b/git_version.php
new file mode 100644 (file)
index 0000000..f304870
--- /dev/null
@@ -0,0 +1,13 @@
+<?php
+if($_GET["git"]){
+       $hash = shell_exec("git --git-dir=/home/git/".$_GET["git"]." rev-list -n 1 --pretty='format:%h' --header master | grep '^[0-9a-f]*$'");
+       $con= shell_exec('git --git-dir=/home/git/'.$_GET["git"].' rev-list --oneline --header master | wc -l | sed "s/[ \t]//g"');
+       if(!$hash){
+               echo "git-0-0";
+       }else{
+               echo "git-".substr($con, 0, -1)."-".substr($hash, 0, -1);
+       }
+}else{
+       echo "404 - No such project";
+}
+?>
diff --git a/gitweb.css b/gitweb.css
new file mode 100644 (file)
index 0000000..417e10f
--- /dev/null
@@ -0,0 +1,631 @@
+body {
+       font-family: sans-serif;
+       font-size: small;
+       border: solid #d9d8d1;
+       border-width: 1px;
+       margin: 10px;
+       background-color: #ffffff;
+       color: #000000;
+}
+
+a {
+       color: #0000cc;
+}
+
+a:hover, a:visited, a:active {
+       color: #880000;
+}
+
+span.cntrl {
+       border: dashed #aaaaaa;
+       border-width: 1px;
+       padding: 0px 2px 0px 2px;
+       margin:  0px 2px 0px 2px;
+}
+
+img.logo {
+       float: right;
+       border-width: 0px;
+}
+
+img.avatar {
+       vertical-align: middle;
+}
+
+a.list img.avatar {
+       border-style: none;
+}
+
+div.page_header {
+       height: 25px;
+       padding: 8px;
+       font-size: 150%;
+       font-weight: bold;
+       background-color: #d9d8d1;
+}
+
+div.page_header a:visited, a.header {
+       color: #0000cc;
+}
+
+div.page_header a:hover {
+       color: #880000;
+}
+
+div.page_nav {
+       padding: 8px;
+}
+
+div.page_nav a:visited {
+       color: #0000cc;
+}
+
+div.page_path {
+       padding: 8px;
+       font-weight: bold;
+       border: solid #d9d8d1;
+       border-width: 0px 0px 1px;
+}
+
+div.page_footer {
+       height: 17px;
+       padding: 4px 8px;
+       background-color: #d9d8d1;
+}
+
+div.page_footer_text {
+       float: left;
+       color: #555555;
+       font-style: italic;
+}
+
+div#generating_info {
+       margin: 4px;
+       font-size: smaller;
+       text-align: center;
+       color: #505050;
+}
+
+div.page_body {
+       padding: 8px;
+       font-family: monospace;
+}
+
+div.title, a.title {
+       display: block;
+       padding: 6px 8px;
+       font-weight: bold;
+       background-color: #edece6;
+       text-decoration: none;
+       color: #000000;
+}
+
+div.readme {
+       padding: 8px;
+}
+
+a.title:hover {
+       background-color: #d9d8d1;
+}
+
+div.title_text {
+       padding: 6px 0px;
+       border: solid #d9d8d1;
+       border-width: 0px 0px 1px;
+       font-family: monospace;
+}
+
+div.log_body {
+       padding: 8px 8px 8px 150px;
+}
+
+span.age {
+       position: relative;
+       float: left;
+       width: 142px;
+       font-style: italic;
+}
+
+span.signoff {
+       color: #888888;
+}
+
+div.log_link {
+       padding: 0px 8px;
+       font-size: 70%;
+       font-family: sans-serif;
+       font-style: normal;
+       position: relative;
+       float: left;
+       width: 136px;
+}
+
+div.list_head {
+       padding: 6px 8px 4px;
+       border: solid #d9d8d1;
+       border-width: 1px 0px 0px;
+       font-style: italic;
+}
+
+.author_date, .author {
+       font-style: italic;
+}
+
+div.author_date {
+       padding: 8px;
+       border: solid #d9d8d1;
+       border-width: 0px 0px 1px 0px;
+}
+
+a.list {
+       text-decoration: none;
+       color: #000000;
+}
+
+a.subject, a.name {
+       font-weight: bold;
+}
+
+table.tags a.subject {
+       font-weight: normal;
+}
+
+a.list:hover {
+       text-decoration: underline;
+       color: #880000;
+}
+
+a.text {
+       text-decoration: none;
+       color: #0000cc;
+}
+
+a.text:visited {
+       text-decoration: none;
+       color: #880000;
+}
+
+a.text:hover {
+       text-decoration: underline;
+       color: #880000;
+}
+
+table {
+       padding: 8px 4px;
+       border-spacing: 0;
+}
+
+table.shortlog td {
+    padding: 0px 8px;
+    vertical-align: middle;
+    height:20px;
+}
+
+img.graph {
+    padding: 0px;
+    margin: 0px;
+    display: block;
+}
+
+table.diff_tree {
+       font-family: monospace;
+}
+
+table.combined.diff_tree th {
+       text-align: center;
+}
+
+table.combined.diff_tree td {
+       padding-right: 24px;
+}
+
+table.combined.diff_tree th.link,
+table.combined.diff_tree td.link {
+       padding: 0px 2px;
+}
+
+table.combined.diff_tree td.nochange a {
+       color: #6666ff;
+}
+
+table.combined.diff_tree td.nochange a:hover,
+table.combined.diff_tree td.nochange a:visited {
+       color: #d06666;
+}
+
+table.blame {
+       border-collapse: collapse;
+}
+
+table.blame td {
+       padding: 0px 5px;
+       font-size: 100%;
+       vertical-align: top;
+}
+
+th {
+       padding: 2px 5px;
+       font-size: 100%;
+       text-align: left;
+}
+
+/* do not change row style on hover for 'blame' view */
+tr.light,
+table.blame .light:hover {
+       background-color: #ffffff;
+}
+
+tr.dark,
+table.blame .dark:hover {
+       background-color: #f6f6f0;
+}
+
+/* currently both use the same, but it can change */
+tr.light:hover,
+tr.dark:hover {
+       background-color: #edece6;
+}
+
+/* boundary commits in 'blame' view */
+/* and commits without "previous" */
+tr.boundary td.sha1,
+tr.no-previous td.linenr {
+       font-weight: bold;
+}
+
+/* for 'blame_incremental', during processing */
+tr.color1 { background-color: #f6fff6; }
+tr.color2 { background-color: #f6f6ff; }
+tr.color3 { background-color: #fff6f6; }
+
+td {
+       padding: 2px 5px;
+       font-size: 100%;
+       vertical-align: top;
+}
+
+td.link, td.selflink {
+       padding: 2px 5px;
+       font-family: sans-serif;
+       font-size: 70%;
+}
+
+td.selflink {
+       padding-right: 0px;
+}
+
+td.sha1 {
+       font-family: monospace;
+}
+
+.error {
+       color: red;
+       background-color: yellow;
+}
+
+td.current_head {
+       text-decoration: underline;
+}
+
+table.diff_tree span.file_status.new {
+       color: #008000;
+}
+
+table.diff_tree span.file_status.deleted {
+       color: #c00000;
+}
+
+table.diff_tree span.file_status.moved,
+table.diff_tree span.file_status.mode_chnge {
+       color: #777777;
+}
+
+table.diff_tree span.file_status.copied {
+  color: #70a070;
+}
+
+/* noage: "No commits" */
+table.project_list td.noage {
+       color: #808080;
+       font-style: italic;
+}
+table.shortlog td.noage, table.history td.noage {
+       color: #808080;
+       font-style: italic;
+}
+
+/* age2: 60*60*24*2 <= age */
+table.project_list td.age2, table.blame td.age2 {
+       font-style: italic;
+}
+table.shortlog td.age2, table.history td.age2 {
+       font-style: italic;
+}
+
+/* age1: 60*60*2 <= age < 60*60*24*2 */
+table.shortlog td.age1, table.project_list td.age1, table.history td.age1 {
+       color: #009900;
+       font-style: italic;
+}
+
+table.blame td.age1 {
+       color: #009900;
+       background: transparent;
+}
+
+/* age0: age < 60*60*2 */
+table.project_list td.age0 {
+       color: #009900;
+       font-style: italic;
+       font-weight: bold;
+}
+table.shortlog td.age0, table.history td.age0 {
+       color: #009900;
+       font-style: italic;
+       font-weight: bold;
+}
+
+table.blame td.age0 {
+       color: #009900;
+       background: transparent;
+       font-weight: bold;
+}
+
+td.pre, div.pre, div.diff {
+       font-family: monospace;
+       font-size: 12px;
+       white-space: pre;
+}
+
+td.mode {
+       font-family: monospace;
+}
+
+/* progress of blame_interactive */
+div#progress_bar {
+       height: 2px;
+       margin-bottom: -2px;
+       background-color: #d8d9d0;
+}
+div#progress_info {
+       float: right;
+       text-align: right;
+}
+
+/* format of (optional) objects size in 'tree' view */
+td.size {
+       font-family: monospace;
+       text-align: right;
+}
+
+/* styling of diffs (patchsets): commitdiff and blobdiff views */
+div.diff.header,
+div.diff.extended_header {
+       white-space: normal;
+}
+
+div.diff.header {
+       font-weight: bold;
+
+       background-color: #edece6;
+
+       margin-top: 4px;
+       padding: 4px 0px 2px 0px;
+       border: solid #d9d8d1;
+       border-width: 1px 0px 1px 0px;
+}
+
+div.diff.header a.path {
+       text-decoration: underline;
+}
+
+div.diff.extended_header,
+div.diff.extended_header a.path,
+div.diff.extended_header a.hash {
+       color: #777777;
+}
+
+div.diff.extended_header .info {
+       color: #b0b0b0;
+}
+
+div.diff.extended_header {
+       background-color: #f6f5ee;
+       padding: 2px 0px 2px 0px;
+}
+
+div.diff a.list,
+div.diff a.path,
+div.diff a.hash {
+       text-decoration: none;
+}
+
+div.diff a.list:hover,
+div.diff a.path:hover,
+div.diff a.hash:hover {
+       text-decoration: underline;
+}
+
+div.diff.to_file a.path,
+div.diff.to_file {
+       color: #007000;
+}
+
+div.diff.add {
+       color: #008800;
+}
+
+div.diff.from_file a.path,
+div.diff.from_file {
+       color: #aa0000;
+}
+
+div.diff.rem {
+       color: #cc0000;
+}
+
+div.diff.chunk_header a,
+div.diff.chunk_header {
+       color: #990099;
+}
+
+div.diff.chunk_header {
+       border: dotted #ffe0ff;
+       border-width: 1px 0px 0px 0px;
+       margin-top: 2px;
+}
+
+div.diff.chunk_header span.chunk_info {
+       background-color: #ffeeff;
+}
+
+div.diff.chunk_header span.section {
+       color: #aa22aa;
+}
+
+div.diff.incomplete {
+       color: #cccccc;
+}
+
+div.diff.nodifferences {
+       font-weight: bold;
+       color: #600000;
+}
+
+div.index_include {
+       border: solid #d9d8d1;
+       border-width: 0px 0px 1px;
+       padding: 12px 8px;
+}
+
+div.search {
+       font-size: 100%;
+       font-weight: normal;
+       margin: 4px 8px;
+       float: right;
+       top: 56px;
+       right: 12px
+}
+
+p.projsearch {
+       text-align: center;
+}
+
+td.linenr {
+       text-align: right;
+}
+
+a.linenr {
+       color: #999999;
+       text-decoration: none
+}
+
+a.rss_logo {
+       float: right;
+       padding: 3px 0px;
+       width: 35px;
+       line-height: 10px;
+       border: 1px solid;
+       border-color: #fcc7a5 #7d3302 #3e1a01 #ff954e;
+       color: #ffffff;
+       background-color: #ff6600;
+       font-weight: bold;
+       font-family: sans-serif;
+       font-size: 70%;
+       text-align: center;
+       text-decoration: none;
+}
+a.rss_logo2 {
+       float: right;
+       padding: 3px 0px;
+       width: 60px;
+       line-height: 10px;
+       border: 1px solid;
+       border-color: #fcc7a5 #7d3302 #3e1a01 #ff954e;
+       color: #ffffff;
+       background-color: #ff6600;
+       font-weight: bold;
+       font-family: sans-serif;
+       font-size: 70%;
+       text-align: center;
+       text-decoration: none;
+}
+
+a.rss_logo:hover {
+       background-color: #ee5500;
+}
+
+a.rss_logo.generic {
+       background-color: #ff8800;
+}
+
+a.rss_logo.generic:hover {
+       background-color: #ee7700;
+}
+
+span.refs span {
+       padding: 0px 4px;
+       font-size: 70%;
+       font-weight: normal;
+       border: 1px solid;
+       background-color: #ffaaff;
+       border-color: #ffccff #ff00ee #ff00ee #ffccff;
+}
+
+span.refs span a {
+       text-decoration: none;
+       color: inherit;
+}
+
+span.refs span a:hover {
+       text-decoration: underline;
+}
+
+span.refs span.indirect {
+       font-style: italic;
+}
+
+span.refs span.ref {
+       background-color: #aaaaff;
+       border-color: #ccccff #0033cc #0033cc #ccccff;
+}
+
+span.refs span.tag {
+       background-color: #ffffaa;
+       border-color: #ffffcc #ffee00 #ffee00 #ffffcc;
+}
+
+span.refs span.head {
+       background-color: #aaffaa;
+       border-color: #ccffcc #00cc33 #00cc33 #ccffcc;
+}
+
+span.atnight {
+       color: #cc0000;
+}
+
+span.match {
+       color: #e00000;
+}
+
+div.binary {
+       font-style: italic;
+}
+
+/* Style definition generated by highlight 2.4.5, http://www.andre-simon.de/ */
+
+/* Highlighting theme definition: */
+
+.num    { color:#2928ff; }
+.esc    { color:#ff00ff; }
+.str    { color:#ff0000; }
+.dstr   { color:#818100; }
+.slc    { color:#838183; font-style:italic; }
+.com    { color:#838183; font-style:italic; }
+.dir    { color:#008200; }
+.sym    { color:#000000; }
+.line   { color:#555555; }
+.kwa    { color:#000000; font-weight:bold; }
+.kwb    { color:#830000; }
+.kwc    { color:#000000; font-weight:bold; }
+.kwd    { color:#010181; }
diff --git a/images/branch_left.png b/images/branch_left.png
new file mode 100644 (file)
index 0000000..06016a1
Binary files /dev/null and b/images/branch_left.png differ
diff --git a/images/branch_right.png b/images/branch_right.png
new file mode 100644 (file)
index 0000000..1db9a66
Binary files /dev/null and b/images/branch_right.png differ
diff --git a/images/dot.png b/images/dot.png
new file mode 100644 (file)
index 0000000..433e75a
Binary files /dev/null and b/images/dot.png differ
diff --git a/images/dot_init.png b/images/dot_init.png
new file mode 100644 (file)
index 0000000..5fbde45
Binary files /dev/null and b/images/dot_init.png differ
diff --git a/images/dot_merge.png b/images/dot_merge.png
new file mode 100644 (file)
index 0000000..70691d0
Binary files /dev/null and b/images/dot_merge.png differ
diff --git a/images/dot_merge_left.png b/images/dot_merge_left.png
new file mode 100644 (file)
index 0000000..0fa7c87
Binary files /dev/null and b/images/dot_merge_left.png differ
diff --git a/images/dot_merge_right.png b/images/dot_merge_right.png
new file mode 100644 (file)
index 0000000..8ccef25
Binary files /dev/null and b/images/dot_merge_right.png differ
diff --git a/images/line.png b/images/line.png
new file mode 100644 (file)
index 0000000..1358887
Binary files /dev/null and b/images/line.png differ
diff --git a/images/line_h.png b/images/line_h.png
new file mode 100644 (file)
index 0000000..0585711
Binary files /dev/null and b/images/line_h.png differ
diff --git a/images/merge_left.png b/images/merge_left.png
new file mode 100644 (file)
index 0000000..cfb950d
Binary files /dev/null and b/images/merge_left.png differ
diff --git a/images/merge_right.png b/images/merge_right.png
new file mode 100644 (file)
index 0000000..67e9d32
Binary files /dev/null and b/images/merge_right.png differ
index 6bb51b6b3aef8d6e4896eb81a5203e79506bed39..8485a90dcf8638ced314b9fa05fc31a8aa06f0e0 100644 (file)
--- a/index.cgi
+++ b/index.cgi
@@ -16,6 +16,7 @@ use Encode;
 use Fcntl ':mode';
 use File::Find qw();
 use File::Basename qw(basename);
+use LWP::Simple;
 binmode STDOUT, ':utf8';
 
 our $t0;
@@ -692,6 +693,10 @@ our %actions = (
        "opml" => \&git_opml,
        "project_list" => \&git_project_list,
        "project_index" => \&git_project_index,
+       "project_index2" => \&git_project_index2,
+       "download" => \&git_download,
+       "downloads" => \&git_downloads,
+       "bugtracker" => \&git_project_bugtracker,
 );
 
 # finally, we have the hash of allowed extra_options for the commands that
@@ -1020,7 +1025,7 @@ sub dispatch {
        if (!defined($actions{$action})) {
                die_error(400, "Unknown action");
        }
-       if ($action !~ m/^(?:opml|project_list|project_index)$/ &&
+       if ($action !~ m/^(?:opml|project_list|project_index2|project_index|downloads)$/ &&
            !$project) {
                die_error(400, "Project needed");
        }
@@ -2720,8 +2725,7 @@ sub git_get_last_activity {
             'refs/heads') or return;
        my $most_recent = <$fd>;
        close $fd or return;
-       if (defined $most_recent &&
-           $most_recent =~ / (\d+) [-+][01]\d\d\d$/) {
+       if (defined $most_recent && $most_recent =~ / (\d+) [-+][01]\d\d\d$/) {
                my $timestamp = $1;
                my $age = time - $timestamp;
                return ($age, age_string($age));
@@ -3552,6 +3556,7 @@ EOF
 
 sub git_footer_html {
        my $feed_class = 'rss_logo';
+       my $feed_class2 = 'rss_logo2';
 
        print "<div class=\"page_footer\">\n";
        if (defined $project) {
@@ -3574,10 +3579,13 @@ sub git_footer_html {
                }
 
        } else {
+               print "<div class=\"page_footer_text\">Copyright &copy; 2012, <a href=\"http://nexus-irc.de\">Nexus-IRC.de</a></div>\n";
                print $cgi->a({-href => href(project=>undef, action=>"opml"),
                              -class => $feed_class}, "OPML") . " ";
                print $cgi->a({-href => href(project=>undef, action=>"project_index"),
-                             -class => $feed_class}, "TXT") . "\n";
+                             -class => $feed_class}, "TXT") . " ";
+               print $cgi->a({-href => href(project=>undef, action=>"downloads"),
+                             -class => $feed_class2}, "Downloads") . "\n";
        }
        print "</div>\n"; # class="page_footer"
 
@@ -3667,7 +3675,7 @@ sub git_print_page_nav {
        my ($current, $suppress, $head, $treehead, $treebase, $extra) = @_;
        $extra = '' if !defined $extra; # pager or formats
 
-       my @navs = qw(summary shortlog log commit commitdiff tree);
+       my @navs = qw(summary bugtracker shortlog log commit commitdiff tree download);
        if ($suppress) {
                @navs = grep { $_ ne $suppress } @navs;
        }
@@ -4650,7 +4658,6 @@ sub git_project_list_body {
                my $cloud = git_populate_project_tagcloud(\%ctags);
                print git_show_project_tagcloud($cloud, 64);
        }
-
        print "<table class=\"project_list\">\n";
        unless ($no_header) {
                print "<tr>\n";
@@ -4704,9 +4711,11 @@ sub git_project_list_body {
                      (defined $pr->{'age_string'} ? $pr->{'age_string'} : "No commits") . "</td>\n" .
                      "<td class=\"link\">" .
                      $cgi->a({-href => href(project=>$pr->{'path'}, action=>"summary")}, "summary")   . " | " .
+                     #$cgi->a({-href => href(project=>$pr->{'path'}, action=>"bugtrack")}, "bugtrack")   . " | " .
                      $cgi->a({-href => href(project=>$pr->{'path'}, action=>"shortlog")}, "shortlog") . " | " .
                      $cgi->a({-href => href(project=>$pr->{'path'}, action=>"log")}, "log") . " | " .
-                     $cgi->a({-href => href(project=>$pr->{'path'}, action=>"tree")}, "tree") .
+                     $cgi->a({-href => href(project=>$pr->{'path'}, action=>"tree")}, "tree") . " | " .
+                     $cgi->a({-href => href(project=>$pr->{'path'}, action=>"download")}, "download") .
                      ($pr->{'forks'} ? " | " . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"forks")}, "forks") : '') .
                      "</td>\n" .
                      "</tr>\n";
@@ -4769,11 +4778,21 @@ sub git_shortlog_body {
        $from = 0 unless defined $from;
        $to = $#{$commitlist} if (!defined $to || $#{$commitlist} < $to);
 
-       print "<table class=\"shortlog\">\n";
+       print "<table class=\"shortlog\" cellspacing=\"0\" cellpadding=\"0\">\n";
        my $alternate = 1;
+       my $graph_rand = int(rand(99999));
        for (my $i = $from; $i <= $to; $i++) {
                my %co = %{$commitlist->[$i]};
                my $commit = $co{'id'};
+               
+               my $head = git_get_head_hash($project);
+               if (!defined $hash) {
+                       $hash = $head;
+               }
+               if (!defined $page) {
+                       $page = 0;
+               }       
+                       
                my $ref = format_ref_marker($refs, $commit);
                if ($alternate) {
                        print "<tr class=\"dark\">\n";
@@ -4782,7 +4801,8 @@ sub git_shortlog_body {
                }
                $alternate ^= 1;
                # git_summary() used print "<td><i>$co{'age_string'}</i></td>\n" .
-               print "<td title=\"$co{'age_string_age'}\"><i>$co{'age_string_date'}</i></td>\n" .
+               print "<td><img class=\"graph\" src=\"git_graph.php?r=".$graph_rand.";p=".$project.";h=".$hash.";from=".($from + (100 * $page)).";to=".($to + (100 * $page)).";c=".$commit."\" /></td>";
+               print "<td class=\"". age_class($co{'age'}) . "\" title=\"$co{'age_string_age'}\"><i>$co{'age_string_date'}</i></td>\n" .
                      format_author_html('td', \%co, 10) . "<td>";
                print format_subject_html($co{'title'}, $co{'title_short'},
                                          href(action=>"commit", hash=>$commit), $ref);
@@ -4831,7 +4851,7 @@ sub git_history_body {
                        print "<tr class=\"light\">\n";
                }
                $alternate ^= 1;
-               print "<td title=\"$co{'age_string_age'}\"><i>$co{'age_string_date'}</i></td>\n" .
+               print "<td class=\"". age_class($co{'age'}) . "\" title=\"$co{'age_string_age'}\"><i>$co{'age_string_date'}</i></td>\n" .
        # shortlog:   format_author_html('td', \%co, 10)
                      format_author_html('td', \%co, 15, 3) . "<td>";
                # originally git_history used chop_str($co{'title'}, 50)
@@ -5098,15 +5118,90 @@ sub git_project_index {
                print "$path $owner\n";
        }
 }
+sub git_project_index2 {
+       my @projects = git_get_projects_list($project);
 
-sub git_summary {
+       print $cgi->header(
+               -type => 'text/plain',
+               -charset => 'utf-8',
+               -content_disposition => 'inline; filename="index.aux"');
+
+       foreach my $pr (@projects) {
+               if (!exists $pr->{'owner'}) {
+                       $pr->{'owner'} = git_get_project_owner("$pr->{'path'}");
+               }
+
+               my ($path, $owner) = ($pr->{'path'}, $pr->{'owner'});
+               # quote as in CGI::Util::encode, but keep the slash, and use '+' for ' '
+               $path  =~ s/([^a-zA-Z0-9_.\-\/ ])/sprintf("%%%02X", ord($1))/eg;
+               $owner =~ s/([^a-zA-Z0-9_.\-\/ ])/sprintf("%%%02X", ord($1))/eg;
+               $path  =~ s/ /\+/g;
+               $owner =~ s/ /\+/g;
+
+               print "$path\n";
+       }
+}
+sub git_downloads {
+       my $dl = get("http://git.nexus-irc.de/git_download.php");
+       git_header_html();
+       print "<div class=\"title\">Downloads</div>\n";
+       print $dl;
+       git_footer_html();
+}
+
+sub git_download {
+       my $dl1 = get("http://git.nexus-irc.de/git_download.php?p=".$project);
+       my %co = parse_commit("HEAD");
+       my $head = $co{'id'};
+       git_header_html();
+       git_print_page_nav('download','', $head);
+       print "<div class=\"title\">Download</div>\n";
+       print $dl1;
+       git_footer_html();
+}
+
+sub git_project_bugtracker {
        my $descr = git_get_project_description($project) || "none";
+       my $bugtrack = get("http://git.nexus-irc.de/git_bugtrack.php?p=".$project);
        my %co = parse_commit("HEAD");
        my %cd = %co ? parse_date($co{'committer_epoch'}, $co{'committer_tz'}) : ();
        my $head = $co{'id'};
+       my $owner = git_get_project_owner($project);    
+       my $version = get("http://git.nexus-irc.de/git_version.php?git=".$project);
+       git_header_html();
+       git_print_page_nav('bugtracker','', $head);
+       print "<div class=\"title\">&nbsp;</div>\n";
+       print "<table class=\"projects_list\">\n" .
+             "<tr id=\"metadata_desc\"><td>description</td><td>" . esc_html($descr) . "</td></tr>\n" .
+             "<tr id=\"metadata_owner\"><td>owner</td><td>" . esc_html($owner) . "</td></tr>\n";
+       if (defined $cd{'rfc2822'}) {
+               print "<tr id=\"metadata_lchange\"><td>last change</td><td>$cd{'rfc2822'}</td></tr>\n";
+       }
+       my $url_tag = "URL";
+       my @url_list = git_get_project_url_list($project);
+       @url_list = map { "$_/$project" } @git_base_url_list unless @url_list;
+       foreach my $git_url (@url_list) {
+               next unless $git_url;
+               print "<tr class=\"metadata_url\"><td>$url_tag</td><td>$git_url</td></tr>\n";
+               $url_tag = "";
+       }
+       print "<tr id=\"metadata_owner\"><td>version</td><td>" . esc_html($version) . "</td></tr>\n";
+       print "</table>\n";
+       git_print_header_div('bugtracker');
+       print $bugtrack;
+       git_footer_html();
+}
 
+sub git_summary {
+       my $descr = git_get_project_description($project) || "none";
+       my %co = parse_commit("HEAD");
+       my %cd = %co ? parse_date($co{'committer_epoch'}, $co{'committer_tz'}) : ();
+       my $head = $co{'id'};
+       
        my $owner = git_get_project_owner($project);
-
+       
+       my $version = get("http://git.nexus-irc.de/git_version.php?git=".$project);
+       
        my $refs = git_get_references();
        # These get_*_list functions return one more to allow us to see if
        # there are more ...
@@ -5121,7 +5216,6 @@ sub git_summary {
 
        git_header_html();
        git_print_page_nav('summary','', $head);
-
        print "<div class=\"title\">&nbsp;</div>\n";
        print "<table class=\"projects_list\">\n" .
              "<tr id=\"metadata_desc\"><td>description</td><td>" . esc_html($descr) . "</td></tr>\n" .
@@ -5140,7 +5234,7 @@ sub git_summary {
                print "<tr class=\"metadata_url\"><td>$url_tag</td><td>$git_url</td></tr>\n";
                $url_tag = "";
        }
-
+       print "<tr id=\"metadata_owner\"><td>version</td><td>" . esc_html($version) . "</td></tr>\n";
        # Tag cloud
        my $show_ctags = gitweb_check_feature('ctags');
        if ($show_ctags) {