7aa9b94f71d4da242a1a86b191a9eed69ae05293
[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   $c->stash(
100       commit => $c->model('GPP')->get_object($c->req->param('h')),
101       action => 'commit',
102   );
103 }
104
105 sub auto : Private {
106     my($self, $c) = @_;
107
108     # XXX Probably not the best place for it but it will do for now.
109     if(my $proj = $c->req->param('p')) {
110         my $m = $c->model('Git');
111         $m->project($proj);
112     }
113
114     # Yes, this is hideous.
115     $self->header($c);
116     $self->footer($c);
117 }
118
119 # XXX This could probably be dropped altogether.
120 use Gitalist::Util qw(to_utf8);
121 # Formally git_header_html
122 sub header {
123   my($self, $c) = @_;
124
125   my $title = $c->config->{sitename};
126
127   my $project   = $c->req->param('project')  || $c->req->param('p');
128   my $action    = $c->req->param('action')   || $c->req->param('a');
129   my $file_name = $c->req->param('filename') || $c->req->param('f');
130   if(defined $project) {
131     $title .= " - " . to_utf8($project);
132     if (defined $action) {
133       $title .= "/$action";
134       if (defined $file_name) {
135         $title .= " - " . $file_name;
136         if ($action eq "tree" && $file_name !~ m|/$|) {
137           $title .= "/";
138         }
139       }
140     }
141   }
142
143   $c->stash->{version}     = $c->config->{version};
144   $c->stash->{git_version} = $c->model('Git')->run_cmd('--version');
145   $c->stash->{title}       = $title;
146
147   #$c->stash->{baseurl} = $ENV{PATH_INFO} && uri_escape($base_url);
148   $c->stash->{stylesheet} = $c->config->{stylesheet} || 'gitweb.css';
149
150   $c->stash->{project} = $project;
151   my @links;
152   if($project) {
153     my %href_params = $self->feed_info($c);
154     $href_params{'-title'} ||= 'log';
155
156     foreach my $format qw(RSS Atom) {
157       my $type = lc($format);
158       push @links, {
159         rel   => 'alternate',
160         title => "$project - $href_params{'-title'} - $format feed",
161
162         # XXX A bit hacky and could do with using gitweb::href() features
163         href  => "?a=$type;p=$project",
164         type  => "application/$type+xml"
165         }, {
166         rel   => 'alternate',
167
168         # XXX This duplication also feels a bit awkward
169         title => "$project - $href_params{'-title'} - $format feed (no merges)",
170         href  => "?a=$type;p=$project;opt=--no-merges",
171         type  => "application/$type+xml"
172         };
173     }
174   } else {
175     push @links, {
176       rel => "alternate",
177       title => $c->config->{sitename}." projects list",
178       href => '?a=project_index',
179       type => "text/plain; charset=utf-8"
180       }, {
181       rel => "alternate",
182       title => $c->config->{sitename}." projects feeds",
183       href => '?a=opml',
184       type => "text/plain; charset=utf-8"
185       };
186   }
187
188   $c->stash->{favicon} = $c->config->{favicon};
189
190   # </head><body>
191
192   $c->stash(
193     logo_url      => $c->config->{logo_url},
194     logo_label    => $c->config->{logo_label},
195     logo_img      => $c->config->{logo},
196     home_link     => $c->config->{home_link},
197     home_link_str => $c->config->{home_link_str},
198     );
199
200   if(defined $project) {
201     $c->stash(
202       search_text => ( $c->req->param('s') || $c->req->param('searchtext') ),
203       search_hash => ( $c->req->param('hb') || $c->req->param('hashbase')
204           || $c->req->param('h')  || $c->req->param('hash')
205           || 'HEAD' ),
206       );
207   }
208 }
209
210 # Formally git_footer_html
211 sub footer {
212   my($self, $c) = @_;
213
214   my $feed_class = 'rss_logo';
215
216   my @feeds;
217   my $project = $c->req->param('project')  || $c->req->param('p');
218   if(defined $project) {
219     (my $pstr = $project) =~ s[/?\.git$][];
220     my $descr = $c->model('Git')->project_info($project)->{description};
221     $c->stash->{project_description} = defined $descr
222       ? $descr
223       : '';
224
225     my %href_params = $self->feed_info($c);
226     if (!%href_params) {
227       $feed_class .= ' generic';
228     }
229     $href_params{'-title'} ||= 'log';
230
231     @feeds = [
232       map +{
233         class => $feed_class,
234         title => "$href_params{'-title'} $_ feed",
235         href  => "/?p=$project;a=\L$_",
236         name  => lc $_,
237         }, qw(RSS Atom)
238       ];
239   } else {
240     @feeds = [
241       map {
242         class => $feed_class,
243           title => '',
244           href  => "/?a=$_->[0]",
245           name  => $_->[1],
246         }, [opml=>'OPML'],[project_index=>'TXT'],
247       ];
248   }
249 }
250
251 # XXX This feels wrong here, should probably be refactored.
252 # returns hash to be passed to href to generate gitweb URL
253 # in -title key it returns description of link
254 sub feed_info {
255   my($self, $c) = @_;
256
257   my $format = shift || 'Atom';
258   my %res = (action => lc($format));
259
260   # feed links are possible only for project views
261   return unless $c->req->param('project');
262
263   # some views should link to OPML, or to generic project feed,
264   # or don't have specific feed yet (so they should use generic)
265   return if $c->req->param('action') =~ /^(?:tags|heads|forks|tag|search)$/x;
266
267   my $branch;
268   my $hash = $c->req->param('h')  || $c->req->param('hash');
269   my $hash_base = $c->req->param('hb') || $c->req->param('hashbase');
270
271   # branches refs uses 'refs/heads/' prefix (fullname) to differentiate
272   # from tag links; this also makes possible to detect branch links
273   if ((defined $hash_base && $hash_base =~ m!^refs/heads/(.*)$!) ||
274     (defined $hash      && $hash      =~ m!^refs/heads/(.*)$!)) {
275     $branch = $1;
276   }
277
278   # find log type for feed description (title)
279   my $type = 'log';
280   my $file_name = $c->req->param('f') || $c->req->param('filename');
281   if (defined $file_name) {
282     $type  = "history of $file_name";
283     $type .= "/" if $c->req->param('action') eq 'tree';
284     $type .= " on '$branch'" if (defined $branch);
285   } else {
286     $type = "log of $branch" if (defined $branch);
287   }
288
289   $res{-title} = $type;
290   $res{'hash'} = (defined $branch ? "refs/heads/$branch" : undef);
291   $res{'file_name'} = $file_name;
292
293   return %res;
294 }
295 =head2 end
296
297 Attempt to render a view, if needed.
298
299 =cut
300
301 sub end : ActionClass('RenderView') {}
302
303 =head1 AUTHOR
304
305 Dan Brook,,,
306
307 =head1 LICENSE
308
309 This library is free software. You can redistribute it and/or modify
310 it under the same terms as Perl itself.
311
312 =cut
313
314 __PACKAGE__->meta->make_immutable;