Move search and reflog and patch actions to the right places
[catagits/Gitalist.git] / lib / Gitalist / Controller / Root.pm
1 package Gitalist::Controller::Root;
2
3 use Moose;
4 use Moose::Autobox;
5 use Sys::Hostname qw/hostname/;
6 use XML::OPML::SimpleGen;
7
8 use Gitalist::Utils qw/ age_string /;
9
10 use namespace::autoclean;
11
12 BEGIN { extends 'Gitalist::Controller' }
13
14 __PACKAGE__->config->{namespace} = '';
15
16 sub root : Chained('/') PathPart('') CaptureArgs(0) {}
17
18 sub _get_object {
19   my($self, $c, $haveh) = @_;
20
21   my $h = $haveh || $c->req->param('h') || '';
22   my $f = $c->req->param('f');
23
24   my $m = $c->stash->{Repository};
25   my $pd = $m->path;
26
27   # Either use the provided h(ash) parameter, the f(ile) parameter or just use HEAD.
28   my $hash = ($h =~ /[^a-f0-9]/ ? $m->head_hash($h) : $h)
29           || ($f && $m->hash_by_path($f))
30           || $m->head_hash
31           # XXX This could definitely use more context.
32           || Carp::croak("Couldn't find a hash for the commit object!");
33
34   my $obj = $m->get_object($hash)
35     or Carp::croak("Couldn't find a object for '$hash' in '$pd'!");
36
37   return $obj;
38 }
39
40 sub index : Chained('base') PathPart('') Args(0) {
41   my ( $self, $c ) = @_;
42
43   $c->detach($c->req->param('a'))
44     if $c->req->param('a');
45
46   my $search = $c->req->param('s') || '';
47
48   $c->stash(
49     search_text => $search,
50   );
51 }
52
53 sub _blob_objs {
54   my ( $self, $c ) = @_;
55   my $repository = $c->stash->{Repository};
56   my $h  = $c->req->param('h')
57        || $repository->hash_by_path($c->req->param('hb'), $c->req->param('f'))
58        || die "No file or sha1 provided.";
59   my $hb = $c->req->param('hb')
60        || $repository->head_hash
61        || die "Couldn't discern the corresponding head.";
62
63   my $filename = $c->req->param('f') || '';
64
65   my $blob = $repository->get_object($h);
66   $blob = $repository->get_object(
67     $repository->hash_by_path($h || $hb, $filename)
68   ) if $blob->type ne 'blob';
69
70   return $blob, $repository->get_object($hb), $filename;
71 }
72
73 =head2 blobdiff_plain
74
75 The plain text version of blobdiff.
76
77 =cut
78
79 sub blobdiff_plain : Chained('base') Args(0) {
80   my($self, $c) = @_;
81
82   $c->stash(no_wrapper => 1);
83   $c->response->content_type('text/plain; charset=utf-8');
84
85   $c->forward('blobdiff');
86 }
87
88 =head2 blobdiff
89
90 Exposes a given diff of a blob.
91
92 =cut
93
94 sub blobdiff : Chained('base') Args(0) {
95   my ( $self, $c ) = @_;
96   my $commit = $self->_get_object($c, $c->req->param('hb'));
97   my $filename = $c->req->param('f')
98               || croak("No file specified!");
99   my($tree, $patch) = $c->stash->{Repository}->diff(
100     commit => $commit,
101     patch  => 1,
102     parent => $c->req->param('hpb') || undef,
103     file   => $filename,
104   );
105   $c->stash(
106     commit    => $commit,
107     diff      => $patch,
108     filename  => $filename,
109     # XXX Hack hack hack, see View::SyntaxHighlight
110     blobs     => [$patch->[0]->{diff}],
111     language  => 'Diff',
112   );
113
114   $c->forward('View::SyntaxHighlight')
115     unless $c->stash->{no_wrapper};
116 }
117
118 # For legacy support.
119 sub history : Chained('base') Args(0) {
120     my ( $self, $c ) = @_;
121     $self->shortlog($c);
122     my $repository = $c->stash->{Repository};
123     my $file = $repository->get_object(
124         $repository->hash_by_path(
125             $repository->head_hash,
126             $c->stash->{filename}
127         )
128     );
129      $c->stash(
130                filetype => $file->type,
131            );
132 }
133
134 =head2 search_help
135
136 Provides some help for the search form.
137
138 =cut
139
140 sub search_help : Chained('base') Args(0) {}
141
142 sub opml : Chained('base') Args(0) {
143   my($self, $c) = @_;
144
145   my $opml = XML::OPML::SimpleGen->new();
146
147   $opml->head(title => lc(hostname()) . ' - ' . Gitalist->config->{name});
148
149   my @list = @{ $c->model()->repositories };
150   die 'No repositories found in '. $c->model->repo_dir
151     unless @list;
152
153   for my $proj ( @list ) {
154     $opml->insert_outline(
155       text   => $proj->name. ' - '. $proj->description,
156       xmlUrl => $c->uri_for(rss => {p => $proj->name}),
157     );
158   }
159
160   $c->response->body($opml->as_string);
161   $c->response->content_type('application/rss');
162   $c->response->status(200);
163 }
164
165 sub base : Chained('/root') PathPart('') CaptureArgs(0) {
166   my($self, $c) = @_;
167
168   my $git_version = `git --version`;
169   chomp($git_version);
170   $c->stash(
171     git_version => $git_version,
172     version     => $Gitalist::VERSION,
173
174     # XXX Move these to a plugin!
175     time_since => sub {
176       return 'never' unless $_[0];
177       return age_string(time - $_[0]->epoch);
178     },
179     short_cmt => sub {
180       my $cmt = shift;
181       my($line) = split /\n/, $cmt;
182       $line =~ s/^(.{70,80}\b).*/$1 \x{2026}/;
183       return $line;
184     },
185     abridged_description => sub {
186         join(' ', grep { defined } (split / /, shift)[0..10]);
187     },
188   );
189 }
190
191 sub end : ActionClass('RenderView') {
192     my ($self, $c) = @_;
193     # Give repository views the current HEAD.
194     if ($c->stash->{Repository}) {
195         $c->stash->{HEAD} = $c->stash->{Repository}->head_hash;
196     }
197 }
198
199 sub error_404 : Action {
200     my ($self, $c) = @_;
201     $c->response->status(404);
202     $c->response->body('Page not found');
203 }
204
205 __PACKAGE__->meta->make_immutable;
206
207 __END__
208
209 =head1 NAME
210
211 Gitalist::Controller::Root - Root controller for the application
212
213 =head1 DESCRIPTION
214
215 This controller handles all of the root level paths for the application
216
217 =head1 METHODS
218
219 =head2 root
220
221 Root of chained actions
222
223 =head2 base
224
225 Populate the header and footer. Perhaps not the best location.
226
227 =head2 index
228
229 Provides the repository listing.
230
231 =head2 end
232
233 Attempt to render a view, if needed.
234
235 =head2 blame
236
237 =head2 error_404
238
239 =head2 history
240
241 =head2 opml
242
243 =head2 repository_index
244
245 =head1 AUTHORS
246
247 See L<Gitalist> for authors.
248
249 =head1 LICENSE
250
251 See L<Gitalist> for the license.
252
253 =cut