Intermediate commit on the way to switching to Git::PurePerl.
[catagits/Gitalist.git] / lib / Gitalist / Controller / Root.pm
1 package Gitalist::Controller::Root;
2 use Moose;
3 use namespace::autoclean;
4
5 BEGIN { extends 'Catalyst::Controller' }
6
7 #
8 # Sets the actions in this controller to be registered with no prefix
9 # so they function identically to actions created in MyApp.pm
10 #
11 __PACKAGE__->config->{namespace} = '';
12
13 =head1 NAME
14
15 Gitalist::Controller::Root - Root Controller for Gitalist
16
17 =head1 DESCRIPTION
18
19 [enter your description here]
20
21 =head1 METHODS
22
23 =cut
24
25 =head2 index
26
27 =cut
28
29 use IO::Capture::Stdout;
30 use File::Slurp qw(slurp);
31
32 sub run_gitweb {
33   my ( $self, $c ) = @_;
34
35   # XXX A slippery slope to be sure.
36   if($c->req->param('a')) {
37     my $capture = IO::Capture::Stdout->new();
38     $capture->start();
39     eval {
40       my $action = gitweb::main($c);
41       $action->();
42     };
43     $capture->stop();
44     
45     use Data::Dumper;
46     die Dumper($@)
47       if $@;
48   
49     my $output = join '', $capture->read;
50     $c->stash->{gitweb_output} = $output;
51     $c->stash->{template} = 'gitweb.tt2';
52   }
53 }
54
55 sub index :Path :Args(0) {
56   my ( $self, $c ) = @_;
57
58   # Leave actions up to gitweb at this point.
59   return $self->run_gitweb($c)
60     if $c->req->param('a');
61
62   my $list = $c->model('Git')->list_projects;
63   unless(@$list) {
64     die "No projects found";
65   }
66
67   $c->stash(
68     searchtext => $c->req->param('searchtext') || '',
69     projects   => $list,
70     action     => 'index',
71   );
72 }
73
74 sub blob : Local {
75   my ( $self, $c ) = @_;
76
77   $c->stash(
78       blob   => $c->model('GPP')->get_object($c->req->param('h'))->content,
79       action => 'blob',
80   );
81 }
82
83 sub reflog : Local {
84   my ( $self, $c ) = @_;
85
86   my @log = $c->model('Git')->reflog(
87       '--since=yesterday'
88   );
89
90   $c->stash(
91       log    => \@log,
92       action => 'reflog',
93   );
94 }
95
96 sub commit {
97   my ( $self, $c ) = @_;
98 }
99
100 sub auto : Private {
101     my($self, $c) = @_;
102
103     # XXX Probably not the best place for it but it will do for now.
104     if(my $proj = $c->req->param('p')) {
105         my $m = $c->model('Git');
106         $m->project($proj);
107     }
108
109     # Yes, this is hideous.
110     $self->header($c);
111     $self->footer($c);
112 }
113
114 # XXX This could probably be dropped altogether.
115 use Gitalist::Util qw(to_utf8);
116 # Formally git_header_html
117 sub header {
118   my($self, $c) = @_;
119
120   my $title = $c->config->{sitename};
121
122   my $project   = $c->req->param('project')  || $c->req->param('p');
123   my $action    = $c->req->param('action')   || $c->req->param('a');
124   my $file_name = $c->req->param('filename') || $c->req->param('f');
125   if(defined $project) {
126     $title .= " - " . to_utf8($project);
127     if (defined $action) {
128       $title .= "/$action";
129       if (defined $file_name) {
130         $title .= " - " . $file_name;
131         if ($action eq "tree" && $file_name !~ m|/$|) {
132           $title .= "/";
133         }
134       }
135     }
136   }
137
138   $c->stash->{version}     = $c->config->{version};
139   $c->stash->{git_version} = $c->model('Git')->run_cmd('--version');
140   $c->stash->{title}       = $title;
141
142   #$c->stash->{baseurl} = $ENV{PATH_INFO} && uri_escape($base_url);
143   $c->stash->{stylesheet} = $c->config->{stylesheet} || 'gitweb.css';
144
145   $c->stash->{project} = $project;
146   my @links;
147   if($project) {
148     my %href_params = $self->feed_info($c);
149     $href_params{'-title'} ||= 'log';
150
151     foreach my $format qw(RSS Atom) {
152       my $type = lc($format);
153       push @links, {
154         rel   => 'alternate',
155         title => "$project - $href_params{'-title'} - $format feed",
156
157         # XXX A bit hacky and could do with using gitweb::href() features
158         href  => "?a=$type;p=$project",
159         type  => "application/$type+xml"
160         }, {
161         rel   => 'alternate',
162
163         # XXX This duplication also feels a bit awkward
164         title => "$project - $href_params{'-title'} - $format feed (no merges)",
165         href  => "?a=$type;p=$project;opt=--no-merges",
166         type  => "application/$type+xml"
167         };
168     }
169   } else {
170     push @links, {
171       rel => "alternate",
172       title => $c->config->{sitename}." projects list",
173       href => '?a=project_index',
174       type => "text/plain; charset=utf-8"
175       }, {
176       rel => "alternate",
177       title => $c->config->{sitename}." projects feeds",
178       href => '?a=opml',
179       type => "text/plain; charset=utf-8"
180       };
181   }
182
183   $c->stash->{favicon} = $c->config->{favicon};
184
185   # </head><body>
186
187   $c->stash(
188     logo_url      => $c->config->{logo_url},
189     logo_label    => $c->config->{logo_label},
190     logo_img      => $c->config->{logo},
191     home_link     => $c->config->{home_link},
192     home_link_str => $c->config->{home_link_str},
193     );
194
195   if(defined $project) {
196     $c->stash(
197       search_text => ( $c->req->param('s') || $c->req->param('searchtext') ),
198       search_hash => ( $c->req->param('hb') || $c->req->param('hashbase')
199           || $c->req->param('h')  || $c->req->param('hash')
200           || 'HEAD' ),
201       );
202   }
203 }
204
205 # Formally git_footer_html
206 sub footer {
207   my($self, $c) = @_;
208
209   my $feed_class = 'rss_logo';
210
211   my @feeds;
212   my $project = $c->req->param('project')  || $c->req->param('p');
213   if(defined $project) {
214     (my $pstr = $project) =~ s[/?\.git$][];
215     my $descr = $c->model('Git')->project_info($project)->{description};
216     $c->stash->{project_description} = defined $descr
217       ? $descr
218       : '';
219
220     my %href_params = $self->feed_info($c);
221     if (!%href_params) {
222       $feed_class .= ' generic';
223     }
224     $href_params{'-title'} ||= 'log';
225
226     @feeds = [
227       map +{
228         class => $feed_class,
229         title => "$href_params{'-title'} $_ feed",
230         href  => "/?p=$project;a=\L$_",
231         name  => lc $_,
232         }, qw(RSS Atom)
233       ];
234   } else {
235     @feeds = [
236       map {
237         class => $feed_class,
238           title => '',
239           href  => "/?a=$_->[0]",
240           name  => $_->[1],
241         }, [opml=>'OPML'],[project_index=>'TXT'],
242       ];
243   }
244 }
245
246 # XXX This feels wrong here, should probably be refactored.
247 # returns hash to be passed to href to generate gitweb URL
248 # in -title key it returns description of link
249 sub feed_info {
250   my($self, $c) = @_;
251
252   my $format = shift || 'Atom';
253   my %res = (action => lc($format));
254
255   # feed links are possible only for project views
256   return unless $c->req->param('project');
257
258   # some views should link to OPML, or to generic project feed,
259   # or don't have specific feed yet (so they should use generic)
260   return if $c->req->param('action') =~ /^(?:tags|heads|forks|tag|search)$/x;
261
262   my $branch;
263   my $hash = $c->req->param('h')  || $c->req->param('hash');
264   my $hash_base = $c->req->param('hb') || $c->req->param('hashbase');
265
266   # branches refs uses 'refs/heads/' prefix (fullname) to differentiate
267   # from tag links; this also makes possible to detect branch links
268   if ((defined $hash_base && $hash_base =~ m!^refs/heads/(.*)$!) ||
269     (defined $hash      && $hash      =~ m!^refs/heads/(.*)$!)) {
270     $branch = $1;
271   }
272
273   # find log type for feed description (title)
274   my $type = 'log';
275   my $file_name = $c->req->param('f') || $c->req->param('filename');
276   if (defined $file_name) {
277     $type  = "history of $file_name";
278     $type .= "/" if $c->req->param('action') eq 'tree';
279     $type .= " on '$branch'" if (defined $branch);
280   } else {
281     $type = "log of $branch" if (defined $branch);
282   }
283
284   $res{-title} = $type;
285   $res{'hash'} = (defined $branch ? "refs/heads/$branch" : undef);
286   $res{'file_name'} = $file_name;
287
288   return %res;
289 }
290 =head2 end
291
292 Attempt to render a view, if needed.
293
294 =cut
295
296 sub end : ActionClass('RenderView') {}
297
298 =head1 AUTHOR
299
300 Dan Brook,,,
301
302 =head1 LICENSE
303
304 This library is free software. You can redistribute it and/or modify
305 it under the same terms as Perl itself.
306
307 =cut
308
309 __PACKAGE__->meta->make_immutable;