From: Dan Brook Date: Tue, 8 Sep 2009 10:40:25 +0000 (+0100) Subject: Further WIP of integrating rafl's work into Gitalist and moving gitweb into Catalyst. X-Git-Tag: 0.000000_01~122 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=04d1d91768a0e0bc6e930a2f5f92972b76722849;p=catagits%2FGitalist.git Further WIP of integrating rafl's work into Gitalist and moving gitweb into Catalyst. --- diff --git a/lib/Gitalist/Controller/Root.pm b/lib/Gitalist/Controller/Root.pm index 78d26f2..365b5a5 100644 --- a/lib/Gitalist/Controller/Root.pm +++ b/lib/Gitalist/Controller/Root.pm @@ -56,27 +56,201 @@ sub index :Path :Args(0) { die "Unknown order parameter"; } - my @list = $c->model('Git')->projects; + my @list = $c->model('Git')->list_projects; if (!@list) { die "No projects found"; } if (-f $c->config->{home_text}) { - print "
\n"; - print slurp($c->config->{home_text}); - print "
\n"; + $c->stash->{home_text_contents} = slurp($c->config->{home_text}); } - my $cgi; - print $cgi->startform(-method => "get") . - "

Search:\n" . - $cgi->textfield(-name => "s", -value => $c->req->param('searchtext')) . "\n" . - "

" . - $cgi->end_form() . "\n"; + $c->config->{ENV} = \%ENV; + $c->stash->{searchtext} = $c->req->param('searchtext'); + $c->stash->{projects} = \@list; + $c->stash->{action} = 'index'; +} + +sub auto : Private { + my($self, $c) = @_; + + # Yes, this is hideous. + $self->header($c); + $self->footer($c); +} + +use Gitalist::Util qw(to_utf8); +use HTML::Entities qw(encode_entities); +use URI::Escape qw(uri_escape); +# Formally git_header_html +sub header { + my($self, $c) = @_; + + my $title = $c->config->{sitename}; + + my $project = $c->req->param('project') || $c->req->param('p'); + my $action = $c->req->param('action') || $c->req->param('a'); + my $file_name = $c->req->param('filename') || $c->req->param('f'); + if(defined $project) { + $title .= " - " . to_utf8($project); + if (defined $action) { + $title .= "/$action"; + if (defined $file_name) { + $title .= " - " . encode_entities($file_name); + if ($action eq "tree" && $file_name !~ m|/$|) { + $title .= "/"; + } + } + } + } + + $c->stash->{version} = $c->config->{version}; + $c->stash->{git_version} = $c->model('Git')->run_cmd('--version'); + $c->stash->{title} = $title; + + #$c->stash->{baseurl} = $ENV{PATH_INFO} && uri_escape($base_url); + $c->stash->{stylesheet} = $c->config->{stylesheet} || 'gitweb.css'; + + $c->stash->{project} = $project; + my @links; + if($project) { + my %href_params = $self->feed_info($c); + $href_params{'-title'} ||= 'log'; + + foreach my $format qw(RSS Atom) { + my $type = lc($format); + push @links, { + rel => 'alternate', + title => "$project - $href_params{'-title'} - $format feed", + # XXX A bit hacky and could do with using gitweb::href() features + href => "?a=$type;p=$project", + type => "application/$type+xml" + }, { + rel => 'alternate', + # XXX This duplication also feels a bit awkward + title => "$project - $href_params{'-title'} - $format feed (no merges)", + href => "?a=$type;p=$project;opt=--no-merges", + type => "application/$type+xml" + }; + } + } else { + push @links, { + rel => "alternate", + title => $c->config->{sitename}." projects list", + href => '?a=project_index', + type => "text/plain; charset=utf-8" + }, { + rel => "alternate", + title => $c->config->{sitename}." projects feeds", + href => '?a=opml', + type => "text/plain; charset=utf-8" + }; + } + + $c->stash->{favicon} = $c->config->{favicon}; + + # - git_project_list_body(\@list, $order); + $c->stash( + logo_url => uri_escape($c->config->{logo_url}), + logo_label => encode_entities($c->config->{logo_label}), + logo_img => $c->config->{logo}, + home_link => uri_escape($c->config->{home_link}), + home_link_str => $c->config->{home_link_str}, + ); + + if(defined $project) { + $c->stash( + search_text => $c->req->param('s') || $c->req->param('searchtext'), + search_hash => $c->req->param('hb') || $c->req->param('hashbase') + || $c->req->param('h') || $c->req->param('hash') + || 'HEAD' + ); + } +} + +# Formally git_footer_html +sub footer { + my($self, $c) = @_; + + my $feed_class = 'rss_logo'; + + my @feeds; + my $project = $c->req->param('project') || $c->req->param('p'); + if(defined $project) { + # ... this could be simpler ... # Chop off .git + my $descr = $c->model('Git')->project_info(substr($project, 0, -5))->{description}; + $c->stash->{project_description} = defined $descr + ? encode_entities($descr) + : ''; + + my %href_params = $self->feed_info($c); + if (!%href_params) { + $feed_class .= ' generic'; + } + $href_params{'-title'} ||= 'log'; + + @feeds = [ + map +{ + class => $feed_class, + title => "$href_params{'-title'} $_ feed", + href => "/?p=$project;a=\L$_", + name => lc $_, + }, qw(RSS Atom) + ]; + } else { + @feeds = [ + map { + class => $feed_class, + title => '', + href => "/?a=$_->[0]", + name => $_->[1], + }, [opml=>'OPML'],[project_index=>'TXT'], + ]; + } } +# XXX This feels wrong here, should probably be refactored. +# returns hash to be passed to href to generate gitweb URL +# in -title key it returns description of link +sub feed_info { + my($self, $c) = @_; + + my $format = shift || 'Atom'; + my %res = (action => lc($format)); + + # feed links are possible only for project views + return unless $c->req->param('project'); + # some views should link to OPML, or to generic project feed, + # or don't have specific feed yet (so they should use generic) + return if $c->req->param('action') =~ /^(?:tags|heads|forks|tag|search)$/x; + + my $branch; + my $hash = $c->req->param('h') || $c->req->param('hash'); + my $hash_base = $c->req->param('hb') || $c->req->param('hashbase'); + # branches refs uses 'refs/heads/' prefix (fullname) to differentiate + # from tag links; this also makes possible to detect branch links + if ((defined $hash_base && $hash_base =~ m!^refs/heads/(.*)$!) || + (defined $hash && $hash =~ m!^refs/heads/(.*)$!)) { + $branch = $1; + } + # find log type for feed description (title) + my $type = 'log'; + my $file_name = $c->req->param('f') || $c->req->param('filename'); + if (defined $file_name) { + $type = "history of $file_name"; + $type .= "/" if $c->req->param('action') eq 'tree'; + $type .= " on '$branch'" if (defined $branch); + } else { + $type = "log of $branch" if (defined $branch); + } + + $res{-title} = $type; + $res{'hash'} = (defined $branch ? "refs/heads/$branch" : undef); + $res{'file_name'} = $file_name; + + return %res; +} =head2 end Attempt to render a view, if needed. diff --git a/lib/Gitalist/Model/Git.pm b/lib/Gitalist/Model/Git.pm index fd8a2a7..d96d1aa 100644 --- a/lib/Gitalist/Model/Git.pm +++ b/lib/Gitalist/Model/Git.pm @@ -14,17 +14,11 @@ use File::Stat::ModeString; use List::MoreUtils qw/any/; use Scalar::Util qw/blessed/; -use Gitalist::Util qw(to_utf8); - -# from gitweb.pm -use CGI::Util qw(unescape); - -has git => ( - is => 'ro', - isa => 'Str', - lazy => 1, - default => sub { - my $git; +{ + my $git; + sub git { + return $git + if $git; if (my $config_git = Gitalist->config->{git}) { $git = $config_git if -x $config_git; @@ -42,14 +36,14 @@ EOR } return $git; - }, -); + } +} sub is_git_repo { my ($self, $dir) = @_; #FIXME: Only handles bare repos. Is that enough? - return -f $dir->file('HEAD'); + return -f $dir->file('HEAD') or -f $dir->file('.git/HEAD'); } sub project_info { @@ -72,10 +66,11 @@ sub get_project_properties { chomp $props{description}; }; - if ($props{description} =~ /^Unnamed repository;/) { + if ($props{description} && $props{description} =~ /^Unnamed repository;/) { delete $props{description}; } + #Carp::cluck "dir is: $dir"; $props{owner} = (getpwuid $dir->stat->uid)[6]; my $output = $self->run_cmd_in($dir, qw{ @@ -144,6 +139,8 @@ sub run_cmd_in { sub git_dir_from_project_name { my ($self, $project) = @_; + warn 'er, dir - '.dir(Gitalist->config->{repo_dir}); + warn 'er, subdir - '.dir(Gitalist->config->{repo_dir})->subdir($project); return dir(Gitalist->config->{repo_dir})->subdir($project); } @@ -343,109 +340,6 @@ sub archive { return $self->run_cmd_in($project, qw/archive --format=tar/, "--prefix=${project}/", $rev); } -## from gitweb.pm - -# checking HEAD file with -e is fragile if the repository was -# initialized long time ago (i.e. symlink HEAD) and was pack-ref'ed -# and then pruned. -sub check_head_link { - my ($dir) = @_; - my $headfile = "$dir/HEAD"; - return ((-e $headfile) || - (-l $headfile && readlink($headfile) =~ /^refs\/heads\//)); -} - -sub check_export_ok { - my ($dir) = @_; - my($export_ok, $export_auth_hook) = @{Gitalist->config}{qw(export_ok export_auth_hook)}; - return (check_head_link($dir) && - (!$export_ok || -e "$dir/$export_ok") && - (!$export_auth_hook || $export_auth_hook->($dir))); -} - -sub projects { - my($self, $filter) = @_; - my @list; - - $filter ||= ''; - $filter =~ s/\.git$//; - - my $projects_list = Gitalist->config->{projectroot}; - if (-d $projects_list) { - # search in directory - my $dir = $projects_list . ($filter ? "/$filter" : ''); - # remove the trailing "/" - $dir =~ s!/+$!!; - my $pfxlen = length("$dir"); - my $pfxdepth = ($dir =~ tr!/!!); - - File::Find::find({ - follow_fast => 1, # follow symbolic links - follow_skip => 2, # ignore duplicates - dangling_symlinks => 0, # ignore dangling symlinks, silently - wanted => sub { - # skip project-list toplevel, if we get it. - return if (m!^[/.]$!); - # only directories can be git repositories - return unless (-d $_); - # don't traverse too deep (Find is super slow on os x) - if (($File::Find::name =~ tr!/!!) - $pfxdepth > Gitalist->config->{project_maxdepth}) { - $File::Find::prune = 1; - return; - } - - my $subdir = substr($File::Find::name, $pfxlen + 1); - # we check related file in $projectroot - my $path = ($filter ? "$filter/" : '') . $subdir; - if (check_export_ok("$projects_list/$path")) { - push @list, { path => $path }; - $File::Find::prune = 1; - } - }, - }, "$dir"); - - } elsif (-f $projects_list) { - # read from file(url-encoded): - # 'git%2Fgit.git Linus+Torvalds' - # 'libs%2Fklibc%2Fklibc.git H.+Peter+Anvin' - # 'linux%2Fhotplug%2Fudev.git Greg+Kroah-Hartman' - my %paths; - open my ($fd), $projects_list or return; - PROJECT: - while (my $line = <$fd>) { - chomp $line; - my ($path, $owner) = split ' ', $line; - $path = unescape($path); - $owner = unescape($owner); - if (!defined $path) { - next; - } - if ($filter ne '') { - # looking for forks; - my $pfx = substr($path, 0, length($filter)); - if ($pfx ne $filter) { - next PROJECT; - } - my $sfx = substr($path, length($filter)); - if ($sfx !~ /^\/.*\.git$/) { - next PROJECT; - } - } - if (check_export_ok("$projects_list/$path")) { - my $pr = { - path => $path, - owner => to_utf8($owner), - }; - push @list, $pr; - (my $forks_path = $path) =~ s/\.git$//; - $paths{$forks_path}++; - } - } - close $fd; - } - return @list; -} - 1; __PACKAGE__->meta->make_immutable; diff --git a/lib/Gitalist/View/Default.pm b/lib/Gitalist/View/Default.pm index 7a9b11e..986ff75 100644 --- a/lib/Gitalist/View/Default.pm +++ b/lib/Gitalist/View/Default.pm @@ -6,6 +6,8 @@ use namespace::autoclean; extends 'Catalyst::View::TT'; with 'Catalyst::View::ContentNegotiation::XHTML'; +use Template::Plugin::Cycle; + =head1 NAME Gitalist::View::Default - Catalyst View @@ -28,8 +30,8 @@ it under the same terms as Perl itself. __PACKAGE__->config( TEMPLATE_EXTENSION => '.tt2', # Set the location for TT files - INCLUDE_PATH => [ Gitalist->path_to( 'templates' ) ], -# WRAPPER => 'default.tt2', + INCLUDE_PATH => [ Gitalist->path_to( 'templates' ) ], + WRAPPER => 'default.tt2', ); __PACKAGE__->meta->make_immutable(inline_constructor => 0); diff --git a/lib/gitweb.pm b/lib/gitweb.pm index bb57fdd..cba8e1b 100755 --- a/lib/gitweb.pm +++ b/lib/gitweb.pm @@ -28,7 +28,7 @@ BEGIN { use vars qw( $cgi $version $my_url $my_uri $base_url $path_info $GIT $projectroot - $project_maxdepth $home_link $home_link_str $site_name $site_header + $project_maxdepth $home_link $home_link_str $site_header $home_text $site_footer @stylesheets $logo_url $logo_label $logo_url $logo_label $projects_list $projects_list_description_width $default_projects_order @@ -93,11 +93,6 @@ sub main { # string of the home link on top of all pages our $home_link_str = "Project Gitalist"; - # name of your site or organization to appear in page titles - # replace this with something more descriptive for clearer bookmarks - our $site_name = "" - || ($ENV{'SERVER_NAME'} || "Untitled") . " Git"; - # filename of html text to include at top of each page our $site_header = ""; # html text to include at home page @@ -2789,7 +2784,7 @@ sub git_header_html { my $status = shift || "200 OK"; my $expires = shift; - my $title = "$site_name"; + my $title = $c->config->{sitename}; if (defined $project) { $title .= " - " . to_utf8($project); if (defined $action) { @@ -2859,10 +2854,10 @@ sub git_header_html { } else { $c->stash->{projects_list} = sprintf(''."\n", - $site_name, href(project=>undef, action=>"project_index")); + $c->config->{sitename}, href(project=>undef, action=>"project_index")); $c->stash->{projects_feed} = sprintf(''."\n", - $site_name, href(project=>undef, action=>"opml")); + $c->config->{sitename}, href(project=>undef, action=>"opml")); } my $favicon = $c->config->{favicon}; @@ -5933,7 +5928,7 @@ sub git_feed { return if ($cgi->request_method() eq 'HEAD'); # header variables - my $title = "$site_name - $project/$action"; + my $title = $c->config->{sitename} . " - $project/$action"; my $feed_type = 'log'; if (defined $hash) { $title .= " - '$hash'"; @@ -6147,11 +6142,12 @@ sub git_opml { -charset => 'utf-8', -content_disposition => 'inline; filename="opml.xml"'); + my $sitename = $c->config->{sitename}; print < - $site_name OPML Export + $sitename OPML Export diff --git a/templates/default.tt2 b/templates/default.tt2 index b6db02c..7a3b5e1 100644 --- a/templates/default.tt2 +++ b/templates/default.tt2 @@ -10,18 +10,20 @@ [% title %] (Gitalist) - [% baseurl %] - [% stylesheets.join("\n") %] - [% IF project; - rss_link; - rss_link_no_merges; - atom_link; - atom_link_no_merges; - ELSE; - projects_list; - projects_feed; - END %] - [% favicon %] + [% IF baseurl %] + + [% END %] + + [% FOR link IN links %] + + [% END %] + [% IF favicon %] + + [% END %] @@ -29,17 +31,30 @@ [% site_header %] [% IF project AND have_search %] [% END %] @@ -51,7 +66,7 @@ END; IF action; - INCLUDE "$action.tt2"; + INCLUDE "index.tt2"; ELSE; # The output of gitweb.cgi is injected at this point. content; @@ -61,18 +76,12 @@ [%- # git_footer_html -%] [% site_footer %]