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