X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FGitalist%2FController%2FRoot.pm;h=892a1d9730ee604b3fd3459d01c535b6885dc196;hb=5921f85bfec434d91f40581e6e0d626d174d9769;hp=f4ab6db8e745749b0577e75cbe9ccabfe8c29332;hpb=ea19a20c43ebc1365ddbbfca835041614f50621b;p=catagits%2FGitalist.git diff --git a/lib/Gitalist/Controller/Root.pm b/lib/Gitalist/Controller/Root.pm index f4ab6db..892a1d9 100644 --- a/lib/Gitalist/Controller/Root.pm +++ b/lib/Gitalist/Controller/Root.pm @@ -1,27 +1,22 @@ package Gitalist::Controller::Root; -use Moose; -use namespace::autoclean; - -BEGIN { extends 'Catalyst::Controller' } - -__PACKAGE__->config->{namespace} = ''; +use Moose; +use Moose::Autobox; use Sys::Hostname (); use XML::Atom::Feed; use XML::Atom::Entry; use XML::RSS; +use XML::OPML::SimpleGen; -=head1 NAME - -Gitalist::Controller::Root - Root Controller for Gitalist +use Gitalist::Utils qw/ age_string /; -=head1 DESCRIPTION +use namespace::autoclean; -[enter your description here] +BEGIN { extends 'Catalyst::Controller' } -=head1 METHODS +__PACKAGE__->config->{namespace} = ''; -=cut +sub root : Chained('/') PathPart('') CaptureArgs(0) {} sub _get_object { my($self, $c, $haveh) = @_; @@ -29,7 +24,7 @@ sub _get_object { my $h = $haveh || $c->req->param('h') || ''; my $f = $c->req->param('f'); - my $m = $c->stash->{Project}; + my $m = $c->stash->{Repository}; my $pd = $m->path; # Either use the provided h(ash) parameter, the f(ile) parameter or just use HEAD. @@ -39,26 +34,20 @@ sub _get_object { # XXX This could definitely use more context. || Carp::croak("Couldn't find a hash for the commit object!"); - my $commit = $m->get_object($hash) - or Carp::croak("Couldn't find a commit object for '$hash' in '$pd'!"); + my $obj = $m->get_object($hash) + or Carp::croak("Couldn't find a object for '$hash' in '$pd'!"); - return $commit; + return $obj; } -=head2 index - -Provides the project listing. - -=cut - -sub index :Path :Args(0) { +sub index : Chained('base') PathPart('') Args(0) { my ( $self, $c ) = @_; $c->detach($c->req->param('a')) if $c->req->param('a'); - my @list = @{ $c->model()->projects }; - die 'No projects found in '. $c->model->repo_dir + my @list = @{ $c->model()->repositories }; + die 'No repositories found in '. $c->model->repo_dir unless @list; my $search = $c->req->param('s') || ''; @@ -71,31 +60,51 @@ sub index :Path :Args(0) { $c->stash( search_text => $search, - projects => \@list, + repositories => \@list, action => 'index', ); } +# FIXME - WTF is this for? +sub repository_index : Chained('base') Args(0) { + my ( $self, $c ) = @_; + + my @list = @{ $c->model()->repositories }; + die 'No repositories found in '. $c->model->repo_dir + unless @list; + + $c->response->content_type('text/plain'); + $c->response->body( + join "\n", map $_->name, @list + ); + $c->response->status(200); +} +# FIXME - maintain compatibility with previous URI +sub project_index : Chained('base') Args(0) { + my ( $self, $c) = @_; + $c->detach('repository_index'); +} + =head2 summary A summary of what's happening in the repo. =cut -sub summary : Local { +sub summary : Chained('base') Args(0) { my ( $self, $c ) = @_; - my $project = $c->stash->{Project}; - $c->detach('error_404') unless $project; + my $repository = $c->stash->{Repository}; + $c->detach('error_404') unless $repository; my $commit = $self->_get_object($c); - my @heads = @{$project->heads}; + my @heads = @{$repository->heads}; my $maxitems = Gitalist->config->{paging}{summary} || 10; $c->stash( commit => $commit, - log_lines => [$project->list_revs( + log_lines => [$repository->list_revs( sha1 => $commit->sha1, count => $maxitems, )], - refs => $project->references, + refs => $repository->references, heads => [ @heads[0 .. ($#heads < $maxitems ? $#heads : $maxitems)] ], action => 'summary', ); @@ -107,12 +116,12 @@ The current list of heads (aka branches) in the repo. =cut -sub heads : Local { +sub heads : Chained('base') Args(0) { my ( $self, $c ) = @_; - my $project = $c->stash->{Project}; + my $repository = $c->stash->{Repository}; $c->stash( commit => $self->_get_object($c), - heads => $project->heads, + heads => $repository->heads, action => 'heads', ); } @@ -123,40 +132,79 @@ The current list of tags in the repo. =cut -sub tags : Local { +sub tags : Chained('base') Args(0) { my ( $self, $c ) = @_; - my $project = $c->stash->{Project}; + my $repository = $c->stash->{Repository}; $c->stash( commit => $self->_get_object($c), - tags => $project->tags, + tags => $repository->tags, action => 'tags', ); } -=head2 blob +sub blame : Chained('base') Args(0) { + my($self, $c) = @_; -The blob action i.e the contents of a file. + my $repository = $c->stash->{Repository}; + my $h = $c->req->param('h') + || $repository->hash_by_path($c->req->param('hb'), $c->req->param('f')) + || die "No file or sha1 provided."; + my $hb = $c->req->param('hb') + || $repository->head_hash + || die "Couldn't discern the corresponding head."; + my $filename = $c->req->param('f') || ''; -=cut + my $blame = $repository->get_object($hb)->blame($filename); + $c->stash( + blame => $blame, + head => $repository->get_object($hb), + filename => $filename, + + # XXX Hack hack hack, see View::SyntaxHighlight + language => ($filename =~ /\.p[lm]$/i ? 'Perl' : ''), + blob => join("\n", map $_->{line}, @$blame), + ); + + $c->forward('View::SyntaxHighlight') + unless $c->stash->{no_wrapper}; +} -sub blob : Local { +sub _blob_objs { my ( $self, $c ) = @_; - my $project = $c->stash->{Project}; + my $repository = $c->stash->{Repository}; my $h = $c->req->param('h') - || $project->hash_by_path($c->req->param('hb'), $c->req->param('f')) + || $repository->hash_by_path($c->req->param('hb'), $c->req->param('f')) || die "No file or sha1 provided."; my $hb = $c->req->param('hb') - || $project->head_hash + || $repository->head_hash || die "Couldn't discern the corresponding head."; my $filename = $c->req->param('f') || ''; + my $blob = $repository->get_object($h); + $blob = $repository->get_object( + $repository->hash_by_path($h || $hb, $filename) + ) if $blob->type ne 'blob'; + + return $blob, $repository->get_object($hb), $filename; +} + +=head2 blob + +The blob action i.e the contents of a file. + +=cut + +sub blob : Chained('base') Args(0) { + my ( $self, $c ) = @_; + + my($blob, $head, $filename) = $self->_blob_objs($c); $c->stash( - blob => $project->get_object($h)->content, - head => $project->get_object($hb), + blob => $blob->content, + head => $head, filename => $filename, # XXX Hack hack hack, see View::SyntaxHighlight - language => ($filename =~ /\.p[lm]$/ ? 'Perl' : ''), + language => ($filename =~ /\.p[lm]$/i ? 'Perl' : ''), action => 'blob', ); @@ -164,23 +212,34 @@ sub blob : Local { unless $c->stash->{no_wrapper}; } -sub blob_plain : Local { +=head2 blob_plain + +The plain text version of blob, where file is rendered as is. + +=cut + +sub blob_plain : Chained('base') Args(0) { my($self, $c) = @_; - $c->stash(no_wrapper => 1); + my($blob) = $self->_blob_objs($c); $c->response->content_type('text/plain; charset=utf-8'); - - $c->forward('blob'); + $c->response->body($blob->content); + $c->response->status(200); } -sub blobdiff_plain : Local { +=head2 blobdiff_plain + +The plain text version of blobdiff. + +=cut + +sub blobdiff_plain : Chained('base') Args(0) { my($self, $c) = @_; $c->stash(no_wrapper => 1); $c->response->content_type('text/plain; charset=utf-8'); $c->forward('blobdiff'); - } =head2 blobdiff @@ -189,12 +248,12 @@ Exposes a given diff of a blob. =cut -sub blobdiff : Local { +sub blobdiff : Chained('base') Args(0) { my ( $self, $c ) = @_; my $commit = $self->_get_object($c, $c->req->param('hb')); my $filename = $c->req->param('f') || croak("No file specified!"); - my($tree, $patch) = $c->stash->{Project}->diff( + my($tree, $patch) = $c->stash->{Repository}->diff( commit => $commit, patch => 1, parent => $c->req->param('hpb') || undef, @@ -203,6 +262,7 @@ sub blobdiff : Local { $c->stash( commit => $commit, diff => $patch, + filename => $filename, # XXX Hack hack hack, see View::SyntaxHighlight blobs => [$patch->[0]->{diff}], language => 'Diff', @@ -219,14 +279,14 @@ Exposes a given commit. =cut -sub commit : Local { +sub commit : Chained('base') Args(0) { my ( $self, $c ) = @_; - my $project = $c->stash->{Project}; + my $repository = $c->stash->{Repository}; my $commit = $self->_get_object($c); $c->stash( commit => $commit, - diff_tree => ($project->diff(commit => $commit))[0], - refs => $project->references, + diff_tree => ($repository->diff(commit => $commit))[0], + refs => $repository->references, action => 'commit', ); } @@ -237,10 +297,10 @@ Exposes a given diff of a commit. =cut -sub commitdiff : Local { +sub commitdiff : Chained('base') Args(0) { my ( $self, $c ) = @_; my $commit = $self->_get_object($c); - my($tree, $patch) = $c->stash->{Project}->diff( + my($tree, $patch) = $c->stash->{Repository}->diff( commit => $commit, parent => $c->req->param('hp') || undef, patch => 1, @@ -259,7 +319,7 @@ sub commitdiff : Local { unless $c->stash->{no_wrapper}; } -sub commitdiff_plain : Local { +sub commitdiff_plain : Chained('base') Args(0) { my($self, $c) = @_; $c->stash(no_wrapper => 1); @@ -274,14 +334,17 @@ Expose an abbreviated log of a given sha1. =cut -sub shortlog : Local { +sub shortlog : Chained('base') Args(0) { my ( $self, $c ) = @_; - my $project = $c->stash->{Project}; - my $commit = $self->_get_object($c); + + my $repository = $c->stash->{Repository}; + my $commit = $self->_get_object($c, $c->req->param('hb')); + my $filename = $c->req->param('f') || ''; + my %logargs = ( sha1 => $commit->sha1, count => Gitalist->config->{paging}{log} || 25, - ($c->req->param('f') ? (file => $c->req->param('f')) : ()) + ($filename ? (file => $filename) : ()) ); my $page = $c->req->param('pg') || 0; @@ -290,10 +353,11 @@ sub shortlog : Local { $c->stash( commit => $commit, - log_lines => [$project->list_revs(%logargs)], - refs => $project->references, - action => 'shortlog', + log_lines => [$repository->list_revs(%logargs)], + refs => $repository->references, page => $page, + filename => $filename, + action => 'shortlog', ); } @@ -302,14 +366,26 @@ sub shortlog : Local { Calls shortlog internally. Perhaps that should be reversed ... =cut -sub log : Local { + +sub log : Chained('base') Args(0) { $_[0]->shortlog($_[1]); $_[1]->stash->{action} = 'log'; } # For legacy support. -sub history : Local { - $_[0]->shortlog(@_[1 .. $#_]); +sub history : Chained('base') Args(0) { + my ( $self, $c ) = @_; + $self->shortlog($c); + my $repository = $c->stash->{Repository}; + my $file = $repository->get_object( + $repository->hash_by_path( + $repository->head_hash, + $c->stash->{filename} + ) + ); + $c->stash( action => 'history', + filetype => $file->type, + ); } =head2 tree @@ -318,15 +394,19 @@ The tree of a given commit. =cut -sub tree : Local { +sub tree : Chained('base') Args(0) { my ( $self, $c ) = @_; - my $project = $c->stash->{Project}; + my $repository = $c->stash->{Repository}; my $commit = $self->_get_object($c, $c->req->param('hb')); - my $tree = $self->_get_object($c, $c->req->param('h') || $commit->tree_sha1); + my $filename = $c->req->param('f') || ''; + my $tree = $filename + ? $repository->get_object($repository->hash_by_path($commit->sha1, $filename)) + : $repository->get_object($commit->tree_sha1) + ; $c->stash( commit => $commit, tree => $tree, - tree_list => [$project->list_tree($tree->sha1)], + tree_list => [$repository->list_tree($tree->sha1)], path => $c->req->param('f') || '', action => 'tree', ); @@ -338,9 +418,9 @@ Expose the local reflog. This may go away. =cut -sub reflog : Local { +sub reflog : Chained('base') Args(0) { my ( $self, $c ) = @_; - my @log = $c->stash->{Project}->reflog( + my @log = $c->stash->{Repository}->reflog( '--since=yesterday' ); @@ -356,10 +436,10 @@ The action for the search form. =cut -sub search : Local { +sub search : Chained('base') Args(0) { my($self, $c) = @_; $c->stash(current_action => 'GitRepos'); - my $project = $c->stash->{Project}; + my $repository = $c->stash->{Repository}; my $commit = $self->_get_object($c); # Lifted from /shortlog. my %logargs = ( @@ -375,7 +455,7 @@ sub search : Local { $c->stash( commit => $commit, - results => [$project->list_revs(%logargs)], + results => [$repository->list_revs(%logargs)], action => 'search', # This could be added - page => $page, ); @@ -387,18 +467,18 @@ Provides some help for the search form. =cut -sub search_help : Local { +sub search_help : Chained('base') Args(0) { my ($self, $c) = @_; $c->stash(template => 'search_help.tt2'); } =head2 atom -Provides an atom feed for a given project. +Provides an atom feed for a given repository. =cut -sub atom : Local { +sub atom : Chained('base') Args(0) { my($self, $c) = @_; my $feed = XML::Atom::Feed->new; @@ -407,15 +487,15 @@ sub atom : Local { $feed->title($host . ' - ' . Gitalist->config->{name}); $feed->updated(~~DateTime->now); - my $project = $c->stash->{Project}; + my $repository = $c->stash->{Repository}; my %logargs = ( - sha1 => $project->head_hash, + sha1 => $repository->head_hash, count => Gitalist->config->{paging}{log} || 25, ($c->req->param('f') ? (file => $c->req->param('f')) : ()) ); my $mk_title = $c->stash->{short_cmt}; - for my $commit ($project->list_revs(%logargs)) { + for my $commit ($repository->list_revs(%logargs)) { my $entry = XML::Atom::Entry->new; $entry->title( $mk_title->($commit->comment) ); $entry->id($c->uri_for('commit', {h=>$commit->sha1})); @@ -431,32 +511,32 @@ sub atom : Local { =head2 rss -Provides an RSS feed for a given project. +Provides an RSS feed for a given repository. =cut -sub rss : Local { +sub rss : Chained('base') Args(0) { my ($self, $c) = @_; - my $project = $c->stash->{Project}; + my $repository = $c->stash->{Repository}; my $rss = XML::RSS->new(version => '2.0'); $rss->channel( title => lc(Sys::Hostname::hostname()) . ' - ' . Gitalist->config->{name}, - link => $c->uri_for('summary', {p=>$project->name}), + link => $c->uri_for('summary', {p=>$repository->name}), language => 'en', - description => $project->description, + description => $repository->description, pubDate => DateTime->now, lastBuildDate => DateTime->now, ); my %logargs = ( - sha1 => $project->head_hash, + sha1 => $repository->head_hash, count => Gitalist->config->{paging}{log} || 25, ($c->req->param('f') ? (file => $c->req->param('f')) : ()) ); my $mk_title = $c->stash->{short_cmt}; - for my $commit ($project->list_revs(%logargs)) { + for my $commit ($repository->list_revs(%logargs)) { # XXX Needs work .... $rss->add_item( title => $mk_title->($commit->comment), @@ -470,13 +550,36 @@ sub rss : Local { $c->response->status(200); } +sub opml : Chained('base') Args(0) { + my($self, $c) = @_; + + my $opml = XML::OPML::SimpleGen->new(); + + $opml->head(title => lc(Sys::Hostname::hostname()) . ' - ' . Gitalist->config->{name}); + + my @list = @{ $c->model()->repositories }; + die 'No repositories found in '. $c->model->repo_dir + unless @list; + + for my $proj ( @list ) { + $opml->insert_outline( + text => $proj->name. ' - '. $proj->description, + xmlUrl => $c->uri_for(rss => {p => $proj->name}), + ); + } + + $c->response->body($opml->as_string); + $c->response->content_type('application/rss'); + $c->response->status(200); +} + =head2 patch A raw patch for a given commit. =cut -sub patch : Local { +sub patch : Chained('base') Args(0) { my ($self, $c) = @_; $c->detach('patches', [1]); } @@ -487,7 +590,7 @@ The patcheset for a given commit ??? =cut -sub patches : Local { +sub patches : Chained('base') Args(0) { my ($self, $c, $count) = @_; $count ||= Gitalist->config->{patches}{max}; my $commit = $self->_get_object($c); @@ -504,12 +607,12 @@ Provides a snapshot of a given commit. =cut -sub snapshot : Local { +sub snapshot : Chained('base') Args(0) { my ($self, $c) = @_; my $format = $c->req->param('sf') || 'tgz'; die unless $format; my $sha1 = $c->req->param('h') || $self->_get_object($c)->sha1; - my @snap = $c->stash->{Project}->snapshot( + my @snap = $c->stash->{Repository}->snapshot( sha1 => $sha1, format => $format ); @@ -519,28 +622,23 @@ sub snapshot : Local { $c->response->body($snap[1]); } -=head2 auto - -Populate the header and footer. Perhaps not the best location. -=cut - -sub auto : Private { +sub base : Chained('/root') PathPart('') CaptureArgs(0) { my($self, $c) = @_; - my $project = $c->req->param('p'); - if (defined $project) { + my $repository = $c->req->param('p'); + if (defined $repository) { eval { - $c->stash(Project => $c->model('GitRepos')->project($project)); + $c->stash(Repository => $c->model('GitRepos')->get_repository($repository)); }; if ($@) { - $c->detach('error_404'); + $c->detach('/error_404'); } } - my $a_project = $c->stash->{Project} || $c->model()->projects->[0]; + my $a_repository = $c->stash->{Repository} || $c->model()->repositories->[0]; $c->stash( - git_version => $a_project->run_cmd('--version'), + git_version => $a_repository->run_cmd('--version'), version => $Gitalist::VERSION, # XXX Move these to a plugin! @@ -551,7 +649,7 @@ sub auto : Private { short_cmt => sub { my $cmt = shift; my($line) = split /\n/, $cmt; - $line =~ s/^(.{70,80}\b).*/$1 …/; + $line =~ s/^(.{70,80}\b).*/$1 \x{2026}/; return $line; }, abridged_description => sub { @@ -560,90 +658,68 @@ sub auto : Private { ); } -sub project_index : Local { - # FIXME - implement snapshot - Carp::croak "Not implemented."; -} -sub opml : Local { - # FIXME - implement snapshot - Carp::croak "Not implemented."; +sub end : ActionClass('RenderView') { + my ($self, $c) = @_; + # Give repository views the current HEAD. + if ($c->stash->{Repository}) { + $c->stash->{HEAD} = $c->stash->{Repository}->head_hash; + } } -sub blame : Local { - # FIXME - implement snapshot - Carp::croak "Not implemented."; + +sub error_404 : Action { + my ($self, $c) = @_; + $c->response->status(404); + $c->response->body('Page not found'); } +__PACKAGE__->meta->make_immutable; + +__END__ + +=head1 NAME + +Gitalist::Controller::Root - Root controller for the application + +=head1 DESCRIPTION + +This controller handles all of the root level paths for the application + +=head1 METHODS + +=head2 root + +Root of chained actions + +=head2 base + +Populate the header and footer. Perhaps not the best location. + +=head2 index + +Provides the repository listing. + =head2 end Attempt to render a view, if needed. -=cut +=head2 blame -sub end : ActionClass('RenderView') { - my ($self, $c) = @_; - # Give project views the current HEAD. - if ($c->stash->{Project}) { - $c->stash->{HEAD} = $c->stash->{Project}->head_hash; - } -} +=head2 commitdiff_plain -sub error_404 :Private { - my ($self, $c) = @_; - $c->response->status(404); - $c->stash( - title => 'Page not found', - content => 'Page not found', - ); -} +=head2 error_404 -sub age_string { - my $age = shift; - my $age_str; +=head2 history - if ( $age > 60 * 60 * 24 * 365 * 2 ) { - $age_str = ( int $age / 60 / 60 / 24 / 365 ); - $age_str .= " years ago"; - } - elsif ( $age > 60 * 60 * 24 * ( 365 / 12 ) * 2 ) { - $age_str = int $age / 60 / 60 / 24 / ( 365 / 12 ); - $age_str .= " months ago"; - } - elsif ( $age > 60 * 60 * 24 * 7 * 2 ) { - $age_str = int $age / 60 / 60 / 24 / 7; - $age_str .= " weeks ago"; - } - elsif ( $age > 60 * 60 * 24 * 2 ) { - $age_str = int $age / 60 / 60 / 24; - $age_str .= " days ago"; - } - elsif ( $age > 60 * 60 * 2 ) { - $age_str = int $age / 60 / 60; - $age_str .= " hours ago"; - } - elsif ( $age > 60 * 2 ) { - $age_str = int $age / 60; - $age_str .= " min ago"; - } - elsif ( $age > 2 ) { - $age_str = int $age; - $age_str .= " sec ago"; - } - else { - $age_str .= " right now"; - } - return $age_str; -} +=head2 opml +=head2 repository_index -=head1 AUTHOR +=head1 AUTHORS -Dan Brook +See L for authors. =head1 LICENSE -This library is free software. You can redistribute it and/or modify -it under the same terms as Perl itself. +See L for the license. =cut - -__PACKAGE__->meta->make_immutable;