gitweb.plon commit first working version (161332a)
   1#!/usr/bin/perl
   2
   3# This file is licensed under the GPL v2, or a later version
   4# (C) 2005, Kay Sievers <kay.sievers@vrfy.org>
   5# (C) 2005, Christian Gierke <ch@gierke.de>
   6
   7use strict;
   8use warnings;
   9use CGI qw(:standard :escapeHTML);
  10use CGI::Carp qw(fatalsToBrowser);
  11
  12my $cgi = new CGI;
  13my $gitbin = "/home/kay/bin";
  14my $gitroot = "/home/kay/public_html";
  15my $gittmp = "/tmp";
  16my $myself = $cgi->url(-relative => 1);
  17
  18my $project = $cgi->param("project") || "";
  19my $action = $cgi->param("action") || "";
  20my $hash = $cgi->param("hash") || "";
  21my $parent = $cgi->param("parent") || "";
  22my $view_back = $cgi->param("view_back") || 60*60*24*2;
  23my $projectroot = "$gitroot/$project";
  24$ENV{'SHA1_FILE_DIRECTORY'} = "$projectroot/.git/objects";
  25
  26$hash =~ s/[^0-9a-fA-F]//g;
  27$parent =~ s/[^0-9a-fA-F]//g;
  28$project =~ s/[^0-9a-zA-Z\-\._]//g;
  29
  30sub header {
  31        print $cgi->header(-type => 'text/html; charset: utf-8');
  32print <<EOF;
  33<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  34<html>
  35<head>
  36        <title>GIT</title>
  37        <style type="text/css">
  38                body { font-family: sans-serif; font-size: 12px; margin:25px; }
  39    div.main { border-width:1px; border-style:solid; border-color:#D9D8D1; }
  40                div.head1 { font-size:20px; padding:8px; background-color: #D9D8D1; font-weight:bold; }
  41                div.head2 { padding:8px;  }
  42                td { padding:8px; margin:0px; font-family: sans-serif; font-size: 12px; }
  43                td.head1 { background-color: #D9D8D1; font-weight:bold; }
  44                td.head2 { background-color: #EDECE6; font-family: monospace; font-size:12px; }
  45                table.log { padding:0px; margin:0px; width:100%; }
  46                tr { vertical-align:top; }
  47    a { color:#0000cc; }
  48    a:hover { color:#880000; }
  49    a:visited { color:#880000; }
  50    a:active { color:#880000; }
  51        </style>
  52</head>
  53<body>
  54EOF
  55        if ($project ne "") {
  56                print "<div class=\"main\">\n";
  57                print "<div class=\"head1\">" . $project . "</div>\n";
  58                print "<div class=\"head2\">\n";
  59                print $cgi->a({-href => "$myself?project=$project&action=show_tree"}, "Browse Project") . "<br/>\n";
  60                print "Show Log ";
  61                print $cgi->a({-href => "$myself?project=$project&action=show_log&view_back=" . 60*60*24}, "day") . "\n";
  62                print $cgi->a({-href => "$myself?project=$project&action=show_log&view_back=" . 60*60*24*7}, "week") . "\n";
  63                print $cgi->a({-href => "$myself?project=$project&action=show_log&view_back=" . 60*60*24*30}, "month") . "\n";
  64                print $cgi->a({-href => "$myself?project=$project&action=show_log&view_back=" . 60*60*24*365}, "year") . "<br/>\n";
  65                print "</div>\n";
  66                print "<br/><br/>\n";
  67        }
  68}
  69
  70sub footer {
  71        print "</div>";
  72        print $cgi->end_html();
  73}
  74
  75if ($project eq "") {
  76        open my $fd, "-|", "ls", "-1", $gitroot;
  77        my (@path) = map { chomp; $_ } <$fd>;
  78        close $fd;
  79        header();
  80        print "Projects:<br/><br/>\n";
  81        foreach my $line (@path) {
  82                if (-e "$gitroot/$line/.git/HEAD") {
  83                        print $cgi->a({-href => "$myself?project=$line"}, $line) . "<br/>\n";
  84                }
  85        }
  86        footer();
  87        exit;
  88}
  89
  90if ($action eq "") {
  91        print $cgi->redirect("$myself?project=$project&action=show_log&view_back=$view_back");
  92        exit;
  93}
  94
  95if ($action eq "show_file") {
  96        header();
  97        print "<pre>\n";
  98        open my $fd, "-|", "$gitbin/cat-file", "blob", $hash;
  99        my $nr;
 100        while (my $line = <$fd>) {
 101                $nr++;
 102                print "$nr\t" . escapeHTML($line);;
 103        }
 104        close $fd;
 105        print "</pre>\n";
 106        footer();
 107} elsif ($action eq "show_tree") {
 108        if ($hash eq "") {
 109                open my $fd, "$projectroot/.git/HEAD";
 110                my $head = <$fd>;
 111                chomp $head;
 112                close $fd;
 113
 114                open $fd, "-|", "$gitbin/cat-file", "commit", $head;
 115                my $tree = <$fd>;
 116                chomp $tree;
 117                $tree =~ s/tree //;
 118                close $fd;
 119                $hash = $tree;
 120        }
 121        open my $fd, "-|", "$gitbin/ls-tree", $hash;
 122        my (@entries) = map { chomp; $_ } <$fd>;
 123        close $fd;
 124        header();
 125        print "<pre>\n";
 126        foreach my $line (@entries) {
 127                $line =~ m/^([0-9]+)\t(.*)\t(.*)\t(.*)$/;
 128                my $t_type = $2;
 129                my $t_hash = $3;
 130                my $t_name = $4;
 131                if ($t_type eq "blob") {
 132                        print "FILE\t" . $cgi->a({-href => "$myself?project=$project&action=show_file&hash=$3"}, $4) . "\n";
 133                } elsif ($t_type eq "tree") {
 134                        print "DIR\t" . $cgi->a({-href => "$myself?project=$project&action=show_tree&hash=$3"}, $4) . "\n";
 135                }
 136        }
 137        print "</pre>\n";
 138        footer();
 139} elsif ($action eq "show_log") {
 140        open my $fd, "$projectroot/.git/HEAD";
 141        my $head = <$fd>;
 142        chomp $head;
 143        close $fd;
 144        open my $fd, "-|", "$gitbin/rev-tree", $head;
 145        my (@revtree) = map { chomp; $_ } <$fd>;
 146        close $fd;
 147        header();
 148        print "<table cellspacing=\"0\" class=\"log\">\n";
 149        foreach my $rev (reverse sort @revtree) {
 150                if (!($rev =~ m/^([0-9]+) ([0-9a-fA-F]+).* ([0-9a-fA-F]+)/)) {
 151                        last;
 152                }
 153                my $time = $1;
 154                my $commit = $2;
 155                my $parent = $3;
 156                my @parents;
 157                my $author;
 158                my $author_name;
 159                my $author_time;
 160                my $author_timezone;
 161                my $committer;
 162                my $committer_time;
 163                my $committer_timezone;
 164                my $tree;
 165                my $comment;
 166                my $shortlog;
 167                open my $fd, "-|", "$gitbin/cat-file", "commit", $commit;
 168                while (my $line = <$fd>) {
 169                        chomp($line);
 170                        if ($line eq "") {
 171                                last;
 172                        }
 173                        if ($line =~ m/^tree (.*)$/) {
 174                                $tree = $1;
 175                        } elsif ($line =~ m/^parent (.*)$/) {
 176                                push @parents, $1;
 177                        } elsif ($line =~ m/^committer (.*>) ([0-9]+) (.*)$/) {
 178                                $committer = $1;
 179                                $committer_time = $2;
 180                                $committer_timezone = $3;
 181                        } elsif ($line =~ m/^author (.*>) ([0-9]+) (.*)$/) {
 182                                $author = $1;
 183                                $author_time = $2;
 184                                $author_timezone = $3;
 185                                $author =~ m/^(.*) </;
 186                                $author_name = $1;
 187                        }
 188                }
 189                $shortlog = <$fd>;
 190                $shortlog = escapeHTML($shortlog);
 191                $comment = $shortlog . "<br/>";
 192                while (my $line = <$fd>) {
 193                                chomp($line);
 194                                $comment .= escapeHTML($line) . "<br/>\n";
 195                }
 196                close $fd;
 197                my $age = time-$author_time;
 198                if ($view_back > 0 && $age > $view_back) {
 199                        last;
 200                }
 201
 202                my $age_string;
 203                if ($age > 60*60*24*365*2) {
 204                        $age_string = int $age/60/60/24/365;
 205                        $age_string .= " years ago";
 206                } elsif ($age > 60*60*24*365/12*2) {
 207                        $age_string = int $age/60/60/24/365/12;
 208                        $age_string .= " months ago";
 209                } elsif ($age > 60*60*24*7*2) {
 210                        $age_string = int $age/60/60/24/7;
 211                        $age_string .= " weeks ago";
 212                } elsif ($age > 60*60*24*2) {
 213                        $age_string = int $age/60/60/24;
 214                        $age_string .= " days ago";
 215                } elsif ($age > 60*60*2) {
 216                        $age_string = int $age/60/60;
 217                        $age_string .= " hours ago";
 218                } elsif ($age > 60*2) {
 219                        $age_string = int $age/60;
 220                        $age_string .= " minutes ago";
 221                }
 222                print "<tr>\n";
 223                print "<td class=\"head1\">" . $age_string . "</td>\n";
 224                print "<td class=\"head1\"><a href=\"$myself?project=$project&amp;action=show_cset&amp;hash=$commit&amp;parent=$parent\">" . $shortlog . "</a></td>";
 225                print "</tr>\n";
 226                print "<tr>\n";
 227                print "<td class=\"head2\"></td>\n";
 228                print "<td class=\"head2\">\n";
 229                print "author &nbsp; &nbsp;" . escapeHTML($author) . " [" . gmtime($author_time) . " " . $author_timezone . "]<br/>\n";
 230                print "committer " . escapeHTML($committer) . " [" . gmtime($committer_time) . " " . $committer_timezone . "]<br/>\n";
 231                print "commit &nbsp; &nbsp;<a href=\"$myself?project=$project&amp;action=show_cset&amp;hash=$commit&amp;parent=$parent\">$commit</a><br/>\n";
 232                print "tree &nbsp; &nbsp; &nbsp;<a href=\"$myself?project=$project&amp;action=show_tree&amp;hash=$tree\">$tree</a><br/>\n";
 233                foreach my $par (@parents) {
 234                        print "parent &nbsp; &nbsp;$par<br/>\n";
 235                }
 236                print "</td>";
 237                print "</tr>\n";
 238                print "<tr>\n";
 239                print "<td></td>\n";
 240                print "<td>\n";
 241                print "$comment<br/><br/>\n";
 242                print "</td>";
 243                print "</tr>\n";
 244        }
 245        print "</table>\n";
 246        footer();
 247} elsif ($action eq "show_cset") {
 248        open my $fd, "-|", "$gitbin/cat-file", "commit", $hash;
 249        my $tree = <$fd>;
 250        chomp $tree;
 251        $tree =~ s/tree //;
 252        close $fd;
 253
 254        open my $fd, "-|", "$gitbin/cat-file", "commit", $parent;
 255        my $parent_tree = <$fd>;
 256        chomp $parent_tree;
 257        $parent_tree =~ s/tree //;
 258        close $fd;
 259
 260        open my $fd, "-|", "$gitbin/diff-tree", "-r", $parent_tree, $tree;
 261        my (@difftree) = map { chomp; $_ } <$fd>;
 262        close $fd;
 263
 264        header();
 265        print "<pre>\n";
 266        foreach my $line (@difftree) {
 267                $line =~ m/^(.)(.*)\t(.*)\t(.*)\t(.*)$/;
 268                my $op = $1;
 269                my $mode = $2;
 270                my $type = $3;
 271                my $id = $4;
 272                my $file = $5;
 273                if ($type eq "blob") {
 274                        if ($op eq "+") {
 275                                print "NEW\t" . $cgi->a({-href => "$myself?project=$project&action=show_file&hash=$id"}, $file) . "\n";
 276                        } elsif ($op eq "-") {
 277                                print "DEL\t" . $cgi->a({-href => "$myself?project=$project&action=show_file&hash=$id"}, $file) . "\n";
 278                        } elsif ($op eq "*") {
 279                                $id =~ m/([0-9a-fA-F]+)->([0-9a-fA-F]+)/;
 280                                my $old = $1;
 281                                my $new = $2;
 282                                print "DIFF\t" . $cgi->a({-href => "$myself?project=$project&action=show_diff&hash=$old&parent=$new"}, $file) . "\n";
 283                        }
 284                }
 285        }
 286        print "</pre>\n";
 287        footer();
 288} elsif ($action eq "show_diff") {
 289        open my $fd2, "> $gittmp/$hash";
 290        open my $fd, "-|", "$gitbin/cat-file", "blob", $hash;
 291        while (my $line = <$fd>) {
 292                print $fd2 $line;
 293        }
 294        close $fd2;
 295        close $fd;
 296
 297        open my $fd2, "> $gittmp/$parent";
 298        open my $fd, "-|", "$gitbin/cat-file", "blob", $parent;
 299        while (my $line = <$fd>) {
 300                print $fd2 $line;
 301        }
 302        close $fd2;
 303        close $fd;
 304
 305        header();
 306        print "<pre>\n";
 307        open my $fd, "-|", "/usr/bin/diff", "-L", "$hash", "-L", "$parent", "-u", "-p", "$gittmp/$hash", "$gittmp/$parent";
 308        while (my $line = <$fd>) {
 309                print escapeHTML($line);
 310        }
 311        close $fd;
 312        unlink("$gittmp/$hash");
 313        unlink("$gittmp/$parent");
 314        print "</pre>\n";
 315        footer();
 316} else {
 317        header();
 318        print "unknown action\n";
 319        footer();
 320}