+Thumbs.db
Gitalist-*
*.swp
git-daemon-export-ok
Makefile
Makefile.old
blib*
-inc*
pm_to_blib
MANIFEST
MANIFEST.bak
This file documents the revision history for Perl extension Gitalist.
+0.001003 2010-04-21
+ - Added folder / file icons in tree view (Foxtons)
+ - Added favicon
+ - Fix for non uri_for hard coded links for running at not root locations.
+ (RT#56747)
+
+0.001002 2010-04-20
+ - Fix link for the project_index action.
+ - Add missing images to MANIFEST.
+
+0.001001 2010-04-15
+ - Bumping version number to a format I understand, thanks to mst for
+ pointing me in the right direction and t0m for the new number.
+ - Cleaned up the search results - removed search from the homepage as
+ wasn't working (Foxtons).
+ - Provide a link for an atom entry. switch mode=xml to type=xhtml (Brian
+ Cassidy).
+
+0.000006.1 2010-04-14
+ - Documentation fixes for the --repo-dir flag (Dagfinn Ilmari Mannsåker).
+
+0.000006 2010-04-10
+ - Major frontend redesign, thanks to ranguard and the web designers at
+ Foxtons for making this happen.
+ - Major URI overhaul, Gitalist has gone from old gitweb style CGI
+ parameters to proper URIs, however the old URIs are still supported
+ and will redirect appropriately (Tomas Doran).
+ - With the URI overhaul also came breaking up actions into fragments
+ for use with Catalyst::View::Component::SubInclude.
+ - BIG BREAKING CHANGE - Gitalist::Model::GitRepos has been renamed
+ Gitalist::Model::CollectionOfRepos. You need to fix your config and
+ if you have actually installed Gitalist - remove the old model file.
+ - Bump required version of Git::PurePerl for Encoding fixes.
+ - Fix Makefile.PL to not need release deps when checking out of Git.
+
0.000005 2010-01-09
+ - Require Git::PurePerl for Win32 compatibility.
- Switch to IPC::Run::start for streamed mode, fixing RT#52658
and the tests with FreeBSD.
- Require new FCGI release in the FCGI script for upstream bug fixes.
- Decode getpwuid values correctly (Dagfinn Ilmari Mannsåker)
- Generate correct provides information in META.yml so that search.cpan
indexes the classes contained in Gitalist correctly.
+ - Dropped the dependency on File::Stat::ModeString
0.000003 2009-12-09
- Officially switch repository to Shadowcat
- Start streamlining and generally rejiging the layout.
- Hacked in syntax highlighting to the blame view.
- Further tweaks to the blame view, making it more informative.
- - Dropped the dependency on File::Stat::ModeString
- Move all POD below the code, for ::Repo and ::Project.
0.000002 2009-12-06
+* Root /search page doesn't do anything
+* Atom feed sucks shit (see t/atom.t)
+* OPML & RSS & Atom Feed dates incorrect format
+* Gitweb compat URIs are borked - there were some I just wholesale ripped out. Put back..
* Sort out commitdiff so conflicted merges have an equivalent display to gitweb (d7f39bebabeb31ce9a7b4f1b6f3db9f391b78c3e as a reference)
* Need to sanitise the input ...
* The snapshot action does not properly support tgz - requests for this format will receive a tar. tbz2 is not supported at all (yet).
#!/usr/bin/env perl
+use FindBin;
+BEGIN { do "$FindBin::Bin/script/env" or die $@ }
+
use strict;
use warnings;
# Fill in provides info so that indexing works right (in the face of MX::Declare)
# by just smashing filenames to package names and not trying to be smart..
File::Find::find(sub {
- return unless $File::Find::name =~ /\.pm$/;
+ return unless /^\w.*?\.pm$/;
my $fn = $File::Find::name;
my $ver = ExtUtils::MM_Unix->parse_version($fn);
requires 'Catalyst::Plugin::StackTrace';
requires 'Catalyst::Plugin::Static::Simple';
requires 'Catalyst::Plugin::Unicode::Encoding';
+requires 'Catalyst::Plugin::SubRequest' => '0.15';
requires 'Catalyst::Action::RenderView';
requires 'Catalyst::Component::InstancePerContext';
+requires 'Catalyst::Controller::ActionRole';
+requires 'Catalyst::View::Component::SubInclude' => '0.07';
requires 'Catalyst::View::TT';
+requires 'Try::Tiny';
requires 'Catalyst::Action::Serialize';
requires 'Template';
requires 'Moose';
requires 'Moose::Autobox';
+requires 'MooseX::MultiMethods' => '0.10';
requires 'MooseX::Declare' => '0.32';
requires 'MooseX::Types::DateTime';
requires 'MooseX::Types::ISO8601';
requires 'MooseX::Types::Path::Class';
requires 'MooseX::Types';
requires 'MooseX::Storage';
-<<<<<<< HEAD
requires 'JSON::Any';
-=======
requires 'JSON::XS';
->>>>>>> origin/json
requires 'namespace::autoclean';
-requires 'Git::PurePerl' => '0.43';
+requires 'Git::PurePerl' => '0.46';
requires 'aliased';
requires 'CGI';
requires 'DateTime';
requires 'DateTime::Format::Mail';
requires 'File::Copy::Recursive';
+requires 'File::Type';
+requires 'File::Type::WebImages';
requires 'File::Which';
requires 'HTML::Entities';
requires 'IPC::Run';
+requires 'JSON::XS';
requires 'List::MoreUtils';
requires 'Path::Class' => '0.17';
requires 'Sub::Exporter';
requires 'Syntax::Highlight::Engine::Kate';
requires 'Sys::Hostname';
-requires 'XML::Atom';
-requires 'XML::RSS';
requires 'XML::OPML::SimpleGen';
+requires 'XML::Atom::Feed';
+requires 'XML::RSS';
test_requires 'Test::More' => '0.88';
test_requires 'Test::utf8' => '0.02';
and die $!;
}
+if ($ENV{GITALIST_RELEASE_TESTING}) {
+ author_tests('t/author');
+ author_requires('Test::NoTabs');
+ author_requires('Test::Pod' => '1.14');
+ author_requires('Test::Pod::Coverage' => '1.04');
+ author_requires('Test::WWW::Mechanize::Catalyst' => '0.51');
+ author_requires('HTML::TreeBuilder::XPath');
+ author_requires('WWW::Mechanize::TreeBuilder');
+}
+
install_script glob('script/*.pl');
auto_install;
The canonical repository for the master branch is:
- it://git.shadowcat.co.uk/catagits/Gitalist.git
+ git://git.shadowcat.co.uk/catagits/Gitalist.git
Gitalist is also mirrored to github, and a number of people have active
forks with branches and/or new features in the master branch.
cp `perl -Ilib -MGitalist -e'print Gitalist->path_to("gitalist.conf")'` gitalist.conf
- You can then edit this confg, adding a repos_dir path and customising
+ You can then edit this confg, adding a repo_dir path and customising
other settings as desired.
You can then start the Gitalist demo server by setting
Alternatively, if you only want to set a repository directory and are
otherwise happy with the default configuration, then you can set the
- "GITALIST_REPOS_DIR" environment variable, or pass the "--repos_dir"
- flag to any of the scripts.
+ "GITALIST_REPO_DIR" environment variable, or pass the "--repo_dir" flag
+ to any of the scripts.
- GITALIST_REPOS_DIR=/home/myuser/code/git gitalist_server.pl
- gitalist_server.pl --repos_dir home/myuser/code/git
+ GITALIST_REPO_DIR=/home/myuser/code/git gitalist_server.pl
+ gitalist_server.pl --repo_dir home/myuser/code/git
- The "GITALIST_REPOS_DIR" environment variable will override the
+ The "GITALIST_REPO_DIR" environment variable will override the
repository directory set in configuration, and will itself be overridden
- by he "--repos_dir" flag.
+ by he "--repo_dir" flag.
RUNNING
Once you have followed the instructions above to install and configure
name Gitalist
-<Model::GitRepos>
+<Model::CollectionOfRepos>
#git /path/to/git
# Configure this to where your repositories are.
# repo_dir __path_to(../)__
-</Model::GitRepos>
+</Model::CollectionOfRepos>
sitename "A Gitalist"
-<Model::GitRepos>
+<Model::CollectionOfRepos>
# This is set so that if you run Gitalist out of a git checkout then you
# can browse the repositories the directory level above your checkout.
# This file is suppressed from the built dist by MANIFEST.SKIP, so you
# don't have this config if you install from CPAN.
repo_dir __path_to(../)__
-</Model::GitRepos>
+</Model::CollectionOfRepos>
Unicode::Encoding
Static::Simple
StackTrace
+ SubRequest
/;
-our $VERSION = '0.000005';
+our $VERSION = '0.001003';
$VERSION = eval $VERSION;
__PACKAGE__->config(
name => 'Gitalist',
default_view => 'Default',
- default_model => 'GitRepos',
+ default_model => 'CollectionOfRepos',
);
__PACKAGE__->setup();
+after prepare_path => sub {
+ my ($ctx) = @_;
+ if ($ctx->req->param('a')) {
+ $ctx->request->uri->path('/legacy' . $ctx->request->uri->path);
+ }
+};
+
around uri_for => sub {
my ($orig, $c) = (shift, shift);
- my $repository_name = $c->stash->{'Repository'} && $c->stash->{'Repository'}->name;
- my $hash = ref($_[-1]) eq 'HASH' ? pop @_ : {};
- my $params = Catalyst::Utils::merge_hashes(
- { p => $hash->{p} || $repository_name },
- $hash,
- );
- delete $params->{p} unless defined $params->{p} && length $params->{p};
- (my $uri = $c->$orig(@_, $params))
- =~ tr[&][;];
+ my $uri = $c->$orig(@_);
+ $$uri =~ tr[&][;] if defined $uri;
return $uri;
};
+around uri_for_action => sub {
+ my ($orig, $c) = (shift, shift);
+ my $uri = $c->$orig(@_);
+ $$uri =~ s[/fragment\b][] if defined $uri;
+ return $uri;
+};
+
+sub uri_with {
+ my ($self, @args) = @_;
+ my $uri = $self->request->uri_with(@args);
+ # Wow this awful.
+ $uri =~ s[/fragment\b][];
+ return $uri;
+}
+
1;
__END__
The canonical repository for the master branch is:
- it://git.shadowcat.co.uk/catagits/Gitalist.git
+ git://git.shadowcat.co.uk/catagits/Gitalist.git
Gitalist is also mirrored to github, and a number of people have active forks
with branches and/or new features in the master branch.
cp `perl -Ilib -MGitalist -e'print Gitalist->path_to("gitalist.conf")'` gitalist.conf
-You can then edit this confg, adding a repos_dir path and customising other settings as desired.
+You can then edit this confg, adding a repo_dir path and customising other settings as desired.
You can then start the Gitalist demo server by setting C<< GITALIST_CONFIG >>. For example:
GITALIST_CONFIG=/usr/local/etc/gitalist.conf gitalist_server.pl
Alternatively, if you only want to set a repository directory and are otherwise happy with
-the default configuration, then you can set the C<< GITALIST_REPOS_DIR >> environment
-variable, or pass the C<< --repos_dir >> flag to any of the scripts.
+the default configuration, then you can set the C<< GITALIST_REPO_DIR >> environment
+variable, or pass the C<< --repo_dir >> flag to any of the scripts.
- GITALIST_REPOS_DIR=/home/myuser/code/git gitalist_server.pl
- gitalist_server.pl --repos_dir home/myuser/code/git
+ GITALIST_REPO_DIR=/home/myuser/code/git gitalist_server.pl
+ gitalist_server.pl --repo_dir home/myuser/code/git
-The C<< GITALIST_REPOS_DIR >> environment variable will override the repository directory set
-in configuration, and will itself be overridden by he C<< --repos_dir >> flag.
+The C<< GITALIST_REPO_DIR >> environment variable will override the repository directory set
+in configuration, and will itself be overridden by he C<< --repo_dir >> flag.
=head1 RUNNING
--- /dev/null
+package Gitalist::ActionRole::FilenameArgs;
+use Moose::Role;
+use namespace::autoclean;
+
+requires 'execute';
+
+before 'execute' => sub {
+ my ($self, $controller, $c, @args) = @_;
+ $c->stash->{filename} = join('/', @args) || ''
+ unless $c->stash->{filename};
+};
+
+1;
+
--- /dev/null
+package Gitalist::ContentMangler::Resolver;
+use Moose::Role;
+
+requires 'resolve';
+
+1;
--- /dev/null
+use MooseX::Declare;
+
+class Gitalist::ContentMangler::Resolver::Default with Gitalist::ContentMangler::Resolver {
+ method resolve ($data) {
+ return unless $data->{filename};
+ my $language = 'Perl' if $data->{filename} =~ /\.p[lm]$/i;
+ return (['SyntaxHighlight', {language => $language, css => $language}]);
+ }
+}
\ No newline at end of file
--- /dev/null
+package Gitalist::Controller;
+use Moose;
+use namespace::autoclean;
+
+BEGIN { extends 'Catalyst::Controller::ActionRole' }
+
+__PACKAGE__->meta->make_immutable;
--- /dev/null
+package Gitalist::Controller::Fragment;
+
+use Moose;
+use namespace::autoclean;
+
+BEGIN { extends 'Gitalist::Controller' }
+
+sub base : Chained('/base') PathPart('fragment') CaptureArgs(0) {
+ my ($self, $c) = @_;
+ $c->stash(no_wrapper => 1);
+}
+
+sub collectionofrepositories : Chained('base') Args(0) {
+ my ($self, $c) = @_;
+ my @list = @{ $c->model()->repositories };
+ die 'No repositories found in '. $c->model->repo_dir
+ unless @list;
+
+ my $search = $c->req->param('s') || '';
+ if($search) {
+ @list = grep {
+ index($_->name, $search) > -1
+ or ( $_->description !~ /^Unnamed repository/ and index($_->description, $search) > -1 )
+ } @list
+ }
+
+ $c->stash(
+ repositories => \@list,
+ );
+}
+
+__PACKAGE__->meta->make_immutable;
--- /dev/null
+package Gitalist::Controller::Fragment::Ref;
+use Moose;
+use namespace::autoclean;
+
+BEGIN { extends 'Gitalist::Controller' }
+with qw/
+ Gitalist::URIStructure::Ref
+ Gitalist::URIStructure::Fragment::WithLog
+/;
+
+use File::Type::WebImages ();
+use JSON::XS qw(encode_json);
+
+sub base : Chained('/fragment/repository/find') PathPart('') CaptureArgs(0) {}
+
+sub _diff {
+ my ($self, $c) = @_;
+ my $commit = $c->stash->{Commit};
+ my %filename = $c->stash->{filename} ? (filename => $c->stash->{filename}) : ();
+ my($tree, $patch) = $c->stash->{Repository}->diff(
+ commit => $commit,
+ parent => $c->stash->{parent},
+ patch => 1,
+ %filename,
+ );
+ $c->stash(
+ diff_tree => $tree,
+ diff => $patch,
+ # XXX Hack hack hack, see View::SyntaxHighlight
+ blobs => [map $_->{diff}, @$patch],
+ %filename,
+ );
+}
+
+after diff_fancy => sub {
+ my ($self, $c) = @_;
+ $self->_diff($c);
+ $c->forward('Model::ContentMangler');
+};
+
+after diff_plain => sub {
+ my ($self, $c) = @_;
+ $self->_diff($c);
+};
+
+after tree => sub {
+ my ( $self, $c ) = @_;
+ my $repository = $c->stash->{Repository};
+ my $commit = $c->stash->{Commit};
+ my $tree = $c->stash->{filename}
+ ? $repository->get_object($repository->hash_by_path($commit->sha1, $c->stash->{filename}))
+ : $repository->get_object($commit->tree_sha1)
+ ;
+ $c->stash(
+ tree => $tree,
+ tree_list => [$repository->list_tree($tree->sha1)],
+ );
+};
+
+after blame => sub {
+ my($self, $c) = @_;
+
+ my $repository = $c->stash->{Repository};
+ # WTF?
+ my $blame = $c->stash->{Commit}->blame($c->stash->{filename}, $c->stash->{Commit}->sha1);
+ $c->stash(
+ blame => $blame,
+ blob => join("\n", map $_->{line}, @$blame),
+ );
+
+ $c->forward('Model::ContentMangler');
+};
+
+=head2 blob
+
+The blob action i.e the contents of a file.
+
+=cut
+
+after blob => sub {
+ my ( $self, $c ) = @_;
+ $c->stash(
+ is_image => File::Type::WebImages::mime_type($c->stash->{blob}),
+ is_binary => Gitalist::Utils::is_binary($c->stash->{blob}),
+ );
+ $c->forward('Model::ContentMangler');
+};
+
+after history => sub {
+ my ($self, $c) = @_;
+ my $repository = $c->stash->{Repository};
+ my $filename = $c->stash->{filename};
+
+ my %logargs = (
+ sha1 => $c->stash->{Commit}->sha1,
+ count => 25, #Gitalist->config->{paging}{log} || 25,
+ ($filename ? (file => $filename) : ())
+ );
+
+ my $file = $repository->get_object(
+ $repository->hash_by_path(
+ $repository->head_hash,
+ $filename
+ )
+ );
+
+ my $page = $c->req->param('pg') || 0;
+ $logargs{skip} = $c->req->param('pg') * $logargs{count}
+ if $c->req->param('pg');
+
+ $c->stash(
+ log_lines => [$repository->list_revs(%logargs)],
+ refs => $repository->references,
+ filename => $filename,
+ filetype => $file->type,
+ );
+};
+
+after file_commit_info => sub {
+ my ($self, $c) = @_;
+
+ my $repository = $c->stash->{Repository};
+
+ my($commit) = $repository->list_revs(
+ sha1 => $c->stash->{Commit}->sha1,
+ count => 1,
+ file => $c->stash->{filename},
+ );
+
+ my $json_obj = !$commit
+ ? { }
+ : {
+ sha1 => $commit->sha1,
+ comment => $c->stash->{short_cmt}->($commit->comment),
+ age => $c->stash->{time_since}->($commit->authored_time),
+ };
+
+ $c->response->content_type('application/json');
+ # XXX Make use of the json branch
+ $c->response->body( encode_json $json_obj );
+};
+
+__PACKAGE__->meta->make_immutable;
--- /dev/null
+package Gitalist::Controller::Fragment::Repository;
+use Moose;
+use namespace::autoclean;
+
+BEGIN { extends 'Gitalist::Controller' }
+with qw/
+ Gitalist::URIStructure::Repository
+ Gitalist::URIStructure::Fragment::WithLog
+/;
+
+sub base : Chained('/fragment/base') PathPart('') CaptureArgs(0) {}
+
+after heads => sub {
+ my ($self, $c) = @_;
+ $c->stash(
+ heads => $c->stash->{Repository}->heads,
+ );
+};
+
+=head2 tags
+
+The current list of tags in the repo.
+
+=cut
+
+after tags => sub {
+ my ( $self, $c ) = @_;
+ $c->stash(
+ tags => $c->stash->{Repository}->tags,
+ );
+};
+
+__PACKAGE__->meta->make_immutable;
--- /dev/null
+package Gitalist::Controller::LegacyURI;
+use Moose;
+use Moose::Autobox;
+use namespace::autoclean;
+
+BEGIN { extends 'Gitalist::Controller' }
+
+my %LEGACY_DISPATCH = (
+ opml => sub { '/opml/opml' },
+ project_index => sub { '/legacyuri/project_index' },
+ '(?:summary|heads|tags)' => sub {
+ my($c, $action, $repos) = @_;
+ return "/repository/$action", [$repos];
+ },
+ blob => sub {
+ my($c, $action, $repos) = @_;
+ my $ref = $c->req->param('hb') || $c->req->param('h');
+ return '/ref/blob', [$repos, $ref], $c->req->param('f');
+ },
+ blob_plain => sub {
+ my($c, $action, $repos) = @_;
+ my $ref = $c->req->param('hb') || $c->req->param('h');
+ return '/ref/raw', [$repos, $ref], $c->req->param('f');
+ },
+ blobdiff => sub {
+ my($c, $action, $repos) = @_;
+ my $ref = $c->req->param('hb') || $c->req->param('h');
+ my $compare = $c->req->param('hbp') || $c->req->param('hp');
+ return '/ref/diff_fancy', [$repos, $ref], $compare, $c->req->param('f');
+ },
+ blobdiff_plain => sub {
+ my($c, $action, $repos) = @_;
+ my $ref = $c->req->param('hb') || $c->req->param('h');
+ my $compare = $c->req->param('hbp') || $c->req->param('hp');
+ return '/ref/diff_plain', [$repos, $ref], $compare, $c->req->param('f');
+ },
+ commit => sub {
+ my($c, $action, $repos) = @_;
+ my $ref = $c->req->param('hb') || $c->req->param('h') || 'HEAD';
+ return '/ref/commit', [$repos, $ref];
+ },
+ # XXX These can be consolidated with the blob equivalents.
+ commitdiff => sub {
+ my($c, $action, $repos) = @_;
+ my $ref = $c->req->param('hb') || $c->req->param('h') || 'HEAD';
+ my $compare = $c->req->param('hbp') || $c->req->param('hp');
+ return '/ref/diff_fancy', [$repos, $ref], $compare, $c->req->param('f');
+ },
+ commitdiff_plain => sub {
+ my($c, $action, $repos) = @_;
+ my $ref = $c->req->param('hb') || $c->req->param('h');
+ my $compare = $c->req->param('hbp') || $c->req->param('hp');
+ return '/ref/diff_plain', [$repos, $ref || 'HEAD'], $compare, $c->req->param('f');
+ },
+ history => sub {
+ my($c, $action, $repos) = @_;
+ my $ref = $c->req->param('hb') || $c->req->param('h') || 'HEAD';
+ return '/ref/history', [$repos, $ref], $c->req->param('f');
+ },
+ log => sub {
+ my($c, $action, $repos) = @_;
+ my $ref = $c->req->param('hb') || $c->req->param('h') || 'HEAD';
+ return '/ref/longlog', [$repos, $ref];
+ },
+ patch => sub {
+ my($c, $action, $repos) = @_;
+ my $ref = $c->req->param('hb') || $c->req->param('h') || 'HEAD';
+ return '/ref/patch', [$repos, $ref];
+ },
+ patches => sub {
+ my($c, $action, $repos) = @_;
+ # XXX Is the arg there wrong? It's just copying G::C::R::patch.
+ return '/ref/patches', [$repos, $c->req->param('h') || 'HEAD'], 1;
+ },
+ search_help => sub {
+ return '/search_help';
+ },
+ shortlog => sub {
+ my($c, $action, $repos) = @_;
+ my $ref = $c->req->param('hb') || $c->req->param('h') || 'HEAD';
+ return '/ref/shortlog', [$repos, $ref];
+ },
+ snapshot => sub {
+ my($c, $action, $repos) = @_;
+ my $ref = $c->req->param('h') || 'HEAD';
+ return '/ref/snapshot', [$repos, $ref], $c->req->param('sf');
+ },
+ tree => sub {
+ my($c, $action, $repos) = @_;
+ my $ref = $c->req->param('hb') || $c->req->param('h') || 'HEAD';
+ return '/ref/tree', [$repos, $ref], $c->req->param('f');
+ },
+ '(?:atom|rss)' => sub {
+ my($c, $action, $repos) = @_;
+ # XXX No support for arbitrary branches or merges/nomerges option :(
+ return "/repository/$action", [$repos], $c->req->param('f');
+ },
+ blame => sub {
+ my($c, $action, $repos) = @_;
+ my $ref = $c->req->param('hb') || $c->req->param('h');
+ return '/ref/blame', [$repos, $ref], $c->req->param('f');
+ },
+);
+
+sub _legacy_uri {
+ my($self, $c, $repos, $action) = @_;
+
+ return
+ unless $action;
+
+ my @result = grep { $action =~ /^$_$/ } keys %LEGACY_DISPATCH;
+ die "Matched too many actions for '$a' - @result"
+ if @result > 1;
+
+ return
+ unless $result[0];
+
+ my($real_action, $captures, @args) = $LEGACY_DISPATCH{$result[0]}->($c, $action, $repos);
+
+ return $real_action, $captures || [], grep defined, @args;
+}
+
+sub handler : Chained('/base') PathPart('legacy') Args() {
+ my ( $self, $c, $repos ) = @_;
+
+ $repos ||= $c->req->param('p');
+
+ my ($action, $captures, @args) = $self->_legacy_uri($c, $repos, $c->req->param('a'));
+
+ die("Not supported")
+ unless $action;
+
+ $c->res->redirect($c->uri_for_action($action, $captures, @args));
+ $c->res->status(301);
+}
+
+sub project_index : Chained('/base') Args(0) {
+ my ( $self, $c ) = @_;
+
+ $c->response->content_type('text/plain');
+ $c->response->body(
+ join "\n", map $_->name, $c->model()->repositories->flatten
+ ) or die 'No repositories found in '. $c->model->repo_dir;
+}
+
+__PACKAGE__->meta->make_immutable;
--- /dev/null
+package Gitalist::Controller::OPML;
+
+use Moose;
+use Moose::Autobox;
+use DateTime;
+use Sys::Hostname qw/hostname/;
+use XML::OPML::SimpleGen;
+
+use namespace::autoclean;
+
+BEGIN { extends 'Gitalist::Controller' }
+
+sub opml : Chained('/base') Args(0) {
+ my ($self, $c) = @_;
+
+ my $opml = XML::OPML::SimpleGen->new();
+
+ $c->stash(
+ title => lc(hostname()) . ' - ' . blessed($c)->config->{name},
+ Repositories => $c->model()->repositories,
+ now => DateTime->now,
+ template => 'opml.tt2',
+ no_wrapper => 1,
+ );
+
+ $c->response->content_type('application/rss');
+}
+
+__PACKAGE__->meta->make_immutable;
--- /dev/null
+package Gitalist::Controller::Ref;
+
+use Moose;
+use namespace::autoclean;
+
+BEGIN { extends 'Gitalist::Controller' }
+with 'Gitalist::URIStructure::Ref';
+
+use File::Type;
+use File::Type::WebImages ();
+
+sub base : Chained('/repository/find') PathPart('') CaptureArgs(0) {}
+
+after commit => sub {
+ my($self, $c) = @_;
+
+ $c->stash->{diff_tree} = ($c->stash->{Repository}->diff(
+ commit => $c->stash->{Commit},
+ ))[0];
+};
+
+sub raw : Chained('find') Does('FilenameArgs') Args() {
+ my ($self, $c) = @_;
+ $c->forward('find_blob');
+
+ if(!Gitalist::Utils::is_binary($c->stash->{blob})) {
+ $c->response->content_type('text/plain; charset=utf-8');
+ } else {
+ my $ft = File::Type->new();
+ $c->response->content_type(
+ File::Type::WebImages::mime_type($c->stash->{blob})
+ || File::Type->new->mime_type($c->stash->{blob})
+ );
+ }
+
+ $c->response->body(delete $c->stash->{blob});
+}
+
+=head2 snapshot
+
+Provides a snapshot of a given commit.
+
+=cut
+
+sub snapshot : Chained('find') PathPart('snapshot') Args() {
+ my ($self, $c, $format) = @_;
+ $format ||= 'tgz';
+ my @snap = $c->stash->{Repository}->snapshot(
+ sha1 => $c->stash->{Commit}->sha1,
+ format => $format
+ );
+ $c->response->status(200);
+ $c->response->headers->header( 'Content-Disposition' =>
+ "attachment; filename=$snap[0]");
+ $c->response->body($snap[1]);
+}
+
+=head2 patch
+
+A raw patch for a given commit.
+
+=cut
+
+sub patch : Chained('find') Args(0) {
+ my ($self, $c) = @_;
+ $c->detach('patches', [1]);
+}
+
+=head2 patches
+
+The patcheset for a given commit ???
+
+=cut
+
+sub patches : Chained('find') Args(1) {
+ my ($self, $c, $count) = @_;
+ $count ||= Gitalist->config->{patches}{max};
+ my $commit = $c->stash->{Commit};
+ my $parent = $c->req->param('hp') || undef; # FIXME
+ my $patch = $commit->get_patch( $parent, $count );
+ $c->response->body($patch);
+ $c->response->content_type('text/plain');
+ $c->response->status(200);
+}
+
+__PACKAGE__->meta->make_immutable;
--- /dev/null
+package Gitalist::Controller::Repository;
+use Moose;
+use XML::Atom::Feed;
+use XML::Atom::Entry;
+use XML::RSS;
+use Sys::Hostname qw/hostname/;
+use namespace::autoclean;
+
+BEGIN { extends 'Gitalist::Controller' }
+with 'Gitalist::URIStructure::Repository';
+
+sub base : Chained('/base') PathPart('') CaptureArgs(0) {}
+
+=head2 search
+
+The action for the search form.
+
+=cut
+
+sub search : Chained('find') Args(0) {
+ my($self, $c) = @_;
+ my $repository = $c->stash->{Repository};
+ # Lifted from /shortlog.
+ my %logargs = (
+ sha1 => $repository->head_hash,
+# count => Gitalist->config->{paging}{log},
+# ($c->req->param('f') ? (file => $c->req->param('f')) : ()),
+ search => {
+ type => $c->req->param('type'),
+ text => $c->req->param('text'),
+ regexp => $c->req->param('regexp') || 0,
+ },
+ );
+
+ $c->stash(
+# commit => $commit,
+ results => [$repository->list_revs(%logargs)],
+ # This could be added - page => $page,
+ );
+}
+
+=head2 tree
+
+Provide a simple redirect to C</ref/tree>.
+
+=cut
+
+sub tree : Chained('find') Args(0) {
+ my($self, $c) = @_;
+ $c->res->redirect($c->uri_for_action('/ref/tree', [$c->stash->{Repository}->name, 'HEAD']));
+ $c->res->status(301);
+}
+
+=head2 atom
+
+Provides an atom feed for a given repository.
+
+=cut
+
+sub atom : Chained('find') Does('FilenameArgs') Args() {
+ my ($self, $c) = @_;
+
+ my $host = lc hostname();
+ $c->stash(
+ title => $host . ' - ' . Gitalist->config->{name},
+ updated => DateTime->now
+ );
+
+ my $repository = $c->stash->{Repository};
+ my %logargs = (
+ sha1 => $repository->head_hash,
+ count => Gitalist->config->{paging}{log} || 25,
+ ($c->stash->{filename} ? (file => $c->stash->{filename}) : ()),
+ );
+
+ my @revs;
+ my $mk_title = $c->stash->{short_cmt};
+ for my $commit ($repository->list_revs(%logargs)) {
+ my $entry = {};
+ $entry->{title} = $mk_title->($commit->comment);
+ $entry->{id} = $c->uri_for_action('/ref/commit', [$repository->name, $commit->sha1]);
+ # XXX FIXME Needs work ...
+ $entry->{content} = $commit->comment;
+ push(@revs, $entry);
+ }
+ $c->stash(
+ Commits => \@revs,
+ no_wrapper => 1,
+ );
+ $c->response->content_type('application/atom+xml');
+}
+
+=head2 rss
+
+Provides an RSS feed for a given repository.
+
+=cut
+
+sub rss : Chained('find') Does('FilenameArgs') Args() {
+ my ($self, $c) = @_;
+
+ my $repository = $c->stash->{Repository};
+
+ $c->stash(
+ title => lc(Sys::Hostname::hostname()) . ' - ' . Gitalist->config->{name},
+ language => 'en',
+ pubDate => DateTime->now,
+ lastBuildDate => DateTime->now,
+ no_wrapper => 1,
+ );
+
+ my %logargs = (
+ sha1 => $repository->head_hash,
+ count => Gitalist->config->{paging}{log} || 25,
+ ($c->stash->{filename} ? (file => $c->stash->{filename}) : ()),
+ );
+ my @revs;
+ my $mk_title = $c->stash->{short_cmt};
+ for my $commit ($repository->list_revs(%logargs)) {
+ # XXX FIXME Needs work ....
+ push(@revs, {
+ title => $mk_title->($commit->comment),
+ permaLink => $c->uri_for_action('/ref/commit', [$repository->name, $commit->sha1]),
+ description => $commit->comment,
+ });
+ }
+ $c->stash(Commits => \@revs);
+ $c->response->content_type('application/rss+xml');
+}
+
+__PACKAGE__->meta->make_immutable;
use Moose;
use Moose::Autobox;
-use Sys::Hostname ();
-use XML::Atom::Feed;
-use XML::Atom::Entry;
-use XML::RSS;
-use XML::OPML::SimpleGen;
-
+use Digest::MD5 qw(md5_hex);
use Gitalist::Utils qw/ age_string /;
use namespace::autoclean;
-BEGIN { extends 'Catalyst::Controller' }
+BEGIN { extends 'Gitalist::Controller' }
-__PACKAGE__->config->{namespace} = '';
+__PACKAGE__->config(namespace => '');
sub root : Chained('/') PathPart('') CaptureArgs(0) {}
-sub _get_object {
- my($self, $c, $haveh) = @_;
-
- my $h = $haveh || $c->req->param('h') || '';
- my $f = $c->req->param('f');
-
- my $m = $c->stash->{Repository};
- my $pd = $m->path;
-
- # Either use the provided h(ash) parameter, the f(ile) parameter or just use HEAD.
- my $hash = ($h =~ /[^a-f0-9]/ ? $m->head_hash($h) : $h)
- || ($f && $m->hash_by_path($f))
- || $m->head_hash
- # XXX This could definitely use more context.
- || Carp::croak("Couldn't find a hash for the commit object!");
-
- my $obj = $m->get_object($hash)
- or Carp::croak("Couldn't find a object for '$hash' in '$pd'!");
-
- return $obj;
-}
-
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()->repositories };
- die 'No repositories found in '. $c->model->repo_dir
- unless @list;
-
- my $search = $c->req->param('s') || '';
- if($search) {
- @list = grep {
- index($_->name, $search) > -1
- or ( $_->description !~ /^Unnamed repository/ and index($_->description, $search) > -1 )
- } @list
- }
-
- $c->stash(
- search_text => $search,
- 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 : Chained('base') Args(0) {
- my ( $self, $c ) = @_;
- my $repository = $c->stash->{data} = $c->stash->{Repository};
- $c->detach('error_404') unless $repository;
- my $commit = $self->_get_object($c);
- my @heads = @{$repository->heads};
- my $maxitems = Gitalist->config->{paging}{summary} || 10;
- $c->stash(
- commit => $commit,
- log_lines => [$repository->list_revs(
- sha1 => $commit->sha1,
- count => $maxitems,
- )],
- refs => $repository->references,
- heads => [ @heads[0 .. ($#heads < $maxitems ? $#heads : $maxitems)] ],
- action => 'summary',
- );
-}
-
-=head2 heads
-
-The current list of heads (aka branches) in the repo.
-
-=cut
-
-sub heads : Chained('base') Args(0) {
- my ( $self, $c ) = @_;
- my $repository = $c->stash->{Repository};
- $c->stash(
- commit => $self->_get_object($c),
- heads => $repository->heads,
- action => 'heads',
- );
-}
-
-=head2 tags
-
-The current list of tags in the repo.
-
-=cut
-
-sub tags : Chained('base') Args(0) {
- my ( $self, $c ) = @_;
- my $repository = $c->stash->{Repository};
- $c->stash(
- commit => $self->_get_object($c),
- tags => $repository->tags,
- action => 'tags',
- );
-}
-
-sub blame : Chained('base') Args(0) {
- my($self, $c) = @_;
-
- 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') || '';
-
- my $blame = $repository->get_object($hb)->blame($filename, $h);
- $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_objs {
- my ( $self, $c ) = @_;
- 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') || '';
-
- 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 => $blob->content,
- head => $head,
- filename => $filename,
- # XXX Hack hack hack, see View::SyntaxHighlight
- language => ($filename =~ /\.p[lm]$/i ? 'Perl' : ''),
- action => 'blob',
- );
-
- $c->forward('View::SyntaxHighlight')
- unless $c->stash->{no_wrapper};
-}
-
-=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) = @_;
-
- my($blob) = $self->_blob_objs($c);
- $c->response->content_type('text/plain; charset=utf-8');
- $c->response->body($blob->content);
- $c->response->status(200);
-}
-
-=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
-
-Exposes a given diff of a blob.
-
-=cut
-
-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->{Repository}->diff(
- commit => $commit,
- patch => 1,
- parent => $c->req->param('hpb') || undef,
- file => $filename,
- );
- $c->stash(
- commit => $commit,
- diff => $patch,
- filename => $filename,
- # XXX Hack hack hack, see View::SyntaxHighlight
- blobs => [$patch->[0]->{diff}],
- language => 'Diff',
- action => 'blobdiff',
- );
-
- $c->forward('View::SyntaxHighlight')
- unless $c->stash->{no_wrapper};
-}
-
-=head2 commit
-
-Exposes a given commit.
-
-=cut
-
-sub commit : Chained('base') Args(0) {
- my ( $self, $c ) = @_;
- my $repository = $c->stash->{Repository};
- my $commit = $self->_get_object($c);
- $c->stash(
- commit => $commit,
- diff_tree => ($repository->diff(commit => $commit))[0],
- refs => $repository->references,
- action => 'commit',
- );
-}
-
-=head2 commitdiff
-
-Exposes a given diff of a commit.
-
-=cut
-
-sub commitdiff : Chained('base') Args(0) {
- my ( $self, $c ) = @_;
- my $commit = $self->_get_object($c);
- my($tree, $patch) = $c->stash->{Repository}->diff(
- commit => $commit,
- parent => $c->req->param('hp') || undef,
- patch => 1,
- );
- $c->stash(
- commit => $commit,
- diff_tree => $tree,
- diff => $patch,
- # XXX Hack hack hack, see View::SyntaxHighlight
- blobs => [map $_->{diff}, @$patch],
- language => 'Diff',
- action => 'commitdiff',
- );
-
- $c->forward('View::SyntaxHighlight')
- unless $c->stash->{no_wrapper};
-}
-
-sub commitdiff_plain : Chained('base') Args(0) {
- my($self, $c) = @_;
-
- $c->stash(no_wrapper => 1);
- $c->response->content_type('text/plain; charset=utf-8');
-
- $c->forward('commitdiff');
-}
-
-=head2 shortlog
-
-Expose an abbreviated log of a given sha1.
-
-=cut
-
-sub shortlog : Chained('base') Args(0) {
- my ( $self, $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,
- ($filename ? (file => $filename) : ())
- );
-
- my $page = $c->req->param('pg') || 0;
- $logargs{skip} = $c->req->param('pg') * $logargs{count}
- if $c->req->param('pg');
-
- $c->stash(
- commit => $commit,
- log_lines => [$repository->list_revs(%logargs)],
- refs => $repository->references,
- page => $page,
- filename => $filename,
- action => 'shortlog',
- );
-}
-
-=head2 log
-
-Calls shortlog internally. Perhaps that should be reversed ...
-
-=cut
-
-sub log : Chained('base') Args(0) {
- $_[0]->shortlog($_[1]);
- $_[1]->stash->{action} = 'log';
-}
-
-# For legacy support.
-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
-
-The tree of a given commit.
-
-=cut
-
-sub tree : Chained('base') Args(0) {
- my ( $self, $c ) = @_;
- my $repository = $c->stash->{Repository};
- my $commit = $self->_get_object($c, $c->req->param('hb'));
- 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 => [$repository->list_tree($tree->sha1)],
- path => $c->req->param('f') || '',
- action => 'tree',
- );
-}
-
-=head2 reflog
-
-Expose the local reflog. This may go away.
-
-=cut
-
-sub reflog : Chained('base') Args(0) {
- my ( $self, $c ) = @_;
- my @log = $c->stash->{Repository}->reflog(
- '--since=yesterday'
- );
-
- $c->stash(
- log => \@log,
- action => 'reflog',
- );
-}
-
-=head2 search
-
-The action for the search form.
-
-=cut
-
-sub search : Chained('base') Args(0) {
- my($self, $c) = @_;
- $c->stash(current_action => 'GitRepos');
- my $repository = $c->stash->{Repository};
- my $commit = $self->_get_object($c);
- # Lifted from /shortlog.
- my %logargs = (
- sha1 => $commit->sha1,
- count => Gitalist->config->{paging}{log},
- ($c->req->param('f') ? (file => $c->req->param('f')) : ()),
- search => {
- type => $c->req->param('type'),
- text => $c->req->param('text'),
- regexp => $c->req->param('regexp') || 0,
- },
- );
-
- $c->stash(
- commit => $commit,
- results => [$repository->list_revs(%logargs)],
- action => 'search',
- # This could be added - page => $page,
- );
-}
-
-=head2 search_help
-
-Provides some help for the search form.
-
-=cut
-
-sub search_help : Chained('base') Args(0) {
- my ($self, $c) = @_;
- $c->stash(template => 'search_help.tt2');
+ $c->stash( search_text => $c->req->param('s') || '' ) # FIXME - XSS?
}
-=head2 atom
-
-Provides an atom feed for a given repository.
-
-=cut
-
-sub atom : Chained('base') Args(0) {
- my($self, $c) = @_;
-
- my $feed = XML::Atom::Feed->new;
-
- my $host = lc Sys::Hostname::hostname();
- $feed->title($host . ' - ' . Gitalist->config->{name});
- $feed->updated(~~DateTime->now);
-
- my $repository = $c->stash->{Repository};
- my %logargs = (
- 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 ($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}));
- # XXX Needs work ...
- $entry->content($commit->comment);
- $feed->add_entry($entry);
- }
-
- $c->response->body($feed->as_xml);
- $c->response->content_type('application/atom+xml');
- $c->response->status(200);
-}
-
-=head2 rss
-
-Provides an RSS feed for a given repository.
-
-=cut
-
-sub rss : Chained('base') Args(0) {
- my ($self, $c) = @_;
-
- 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=>$repository->name}),
- language => 'en',
- description => $repository->description,
- pubDate => DateTime->now,
- lastBuildDate => DateTime->now,
- );
-
- my %logargs = (
- 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 ($repository->list_revs(%logargs)) {
- # XXX Needs work ....
- $rss->add_item(
- title => $mk_title->($commit->comment),
- permaLink => $c->uri_for(commit => {h=>$commit->sha1}),
- description => $commit->comment,
- );
- }
-
- $c->response->body($rss->as_string);
- $c->response->content_type('application/rss+xml');
- $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 : Chained('base') Args(0) {
- my ($self, $c) = @_;
- $c->detach('patches', [1]);
-}
-
-=head2 patches
-
-The patcheset for a given commit ???
-
-=cut
-
-sub patches : Chained('base') Args(0) {
- my ($self, $c, $count) = @_;
- $count ||= Gitalist->config->{patches}{max};
- my $commit = $self->_get_object($c);
- my $parent = $c->req->param('hp') || undef;
- my $patch = $commit->get_patch( $parent, $count );
- $c->response->body($patch);
- $c->response->content_type('text/plain');
- $c->response->status(200);
-}
-
-=head2 snapshot
-
-Provides a snapshot of a given commit.
-
-=cut
+# XXX Fragile much?
+sub css : Chained('/root') PathPart('core.css') Args(0) {
+ my ( $self, $c ) = @_;
-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->{Repository}->snapshot(
- sha1 => $sha1,
- format => $format
- );
- $c->response->status(200);
- $c->response->headers->header( 'Content-Disposition' =>
- "attachment; filename=$snap[0]");
- $c->response->body($snap[1]);
+ $c->response->content_type('text/css');
+ $c->stash(template => 'static/css/core.css');
}
-
sub base : Chained('/root') PathPart('') CaptureArgs(0) {
my($self, $c) = @_;
- my $repository = $c->req->param('p');
- if (defined $repository) {
- eval {
- $c->stash(Repository => $c->model('GitRepos')->get_repository($repository));
- };
- if ($@) {
- $c->detach('/error_404');
- }
- }
-
- my $a_repository = $c->stash->{Repository} || $c->model()->repositories->[0];
+ my $git_version = `git --version`;
+ chomp($git_version);
$c->stash(
- git_version => $a_repository->run_cmd('--version'),
+ git_version => $git_version,
version => $Gitalist::VERSION,
# XXX Move these to a plugin!
short_cmt => sub {
my $cmt = shift;
my($line) = split /\n/, $cmt;
- $line =~ s/^(.{70,80}\b).*/$1 \x{2026}/;
+ $line =~ s/^(.{70,80}\b).*/$1 \x{2026}/ if defined $line;
return $line;
},
abridged_description => sub {
join(' ', grep { defined } (split / /, shift)[0..10]);
},
+ uri_for_gravatar => sub { # FIXME - Cache these?
+ my $email = shift;
+ my $size = shift;
+ my $uri = 'http://www.gravatar.com/avatar/' . md5_hex($email);
+ $uri .= "?s=$size" if $size;
+ return $uri;
+ },
);
}
Attempt to render a view, if needed.
-=head2 blame
-
-=head2 commitdiff_plain
-
=head2 error_404
-=head2 history
-
-=head2 opml
-
-=head2 repository_index
-
=head1 AUTHORS
See L<Gitalist> for authors.
method diff ( Maybe[Bool] :$patch?,
Maybe[NonEmptySimpleStr] :$parent?,
- Maybe[NonEmptySimpleStr] :$file?
+ Maybe[NonEmptySimpleStr] :$filename?
) {
$parent = $parent
? $parent
? $self->parent_sha1
: '-c';
my @etc = (
- ( $file ? ('--', $file) : () ),
+ ( $filename ? ('--', $filename) : () ),
);
my @out = $self->_raw_diff(
$line{sha1} = $line{sha1dst};
$line{is_new} = $line{sha1src} =~ /^0+$/
if $line{sha1src};
- @line{qw/status sim/} = $line{status} =~ /(R)(\d+)/
+ @line{qw/status sim/} = $line{status} =~ /(R)0*(\d+)/
if $line{status} =~ /^R/;
push @ret, \%line;
}
next;
}
- if (/^index (\w+)\.\.(\w+) (\d+)$/) {
+ if (/^index (\w+)\.\.(\w+)(?: (\d+))?$/) {
@{$ret[-1]}{qw(index src dst mode)} = ($_, $1, $2, $3);
next
}
# FIXME, use Types::Path::Class and coerce
use MooseX::Types::Common::String qw/NonEmptySimpleStr/;
use MooseX::Types::Moose qw/Str Maybe Bool HashRef ArrayRef/;
+ use MooseX::MultiMethods;
use Gitalist::Git::Types qw/SHA1 DateTime Dir/;
use Moose::Autobox;
use List::MoreUtils qw/any zip/;
}
## Public methods
+
+ multi method get_object_or_head (SHA1 $sha1) {
+ $self->get_object($sha1);
+ }
+ multi method get_object_or_head (NonEmptySimpleStr $ref) {
+ my $sha1 = $self->head_hash($ref);
+ $self->get_object($sha1);
+ }
+
method head_hash (Str $head?) {
my $output = $self->run_cmd(qw/rev-parse --verify/, $head || 'HEAD' );
confess("No such head: " . $head) unless defined $output;
if !$sha1 || $sha1 !~ $SHA1RE;
my @search_opts;
- if ($search) {
+ if ($search and exists $search->{text}) {
$search->{type} = 'grep'
if $search->{type} eq 'commit';
@search_opts = (
method diff ( Gitalist::Git::Object :$commit!,
Bool :$patch?,
Maybe[NonEmptySimpleStr] :$parent?,
- NonEmptySimpleStr :$file?
+ NonEmptySimpleStr :$filename?
) {
return $commit->diff( patch => $patch,
parent => $parent,
- file => $file);
+ filename => $filename);
}
method reflog (@logargs) {
$description = $self->path->file('description')->slurp;
chomp $description;
};
+ $description = "Unnamed repository, edit the .git/description file to set a description"
+ if $description eq "Unnamed repository; edit this file 'description' to name the repository.";
return $description;
}
-package Gitalist::Model::GitRepos;
+package Gitalist::Model::CollectionOfRepos;
use Moose;
use Gitalist::Git::CollectionOfRepositories::FromDirectory;
--- /dev/null
+package Gitalist::Model::ContentMangler;
+use Moose;
+use MooseX::Types::Moose qw/HashRef/;
+use MooseX::Types::Common::String qw/NonEmptySimpleStr/;
+use Gitalist::ContentMangler::Resolver;
+use namespace::autoclean;
+
+extends 'Catalyst::Model';
+
+has resolver_class => (
+ isa => NonEmptySimpleStr,
+ is => 'ro',
+ required => 1,
+ default => 'Gitalist::ContentMangler::Resolver::Default',
+);
+
+has resolver_config => (
+ isa => HashRef,
+ is => 'ro',
+ default => sub { {} },
+);
+
+has _resolver => (
+ does => 'Gitalist::ContentMangler::Resolver',
+ handles => ['resolve'],
+ is => 'bare', lazy => 1,
+ default => sub {
+ my $self = shift;
+ my $class = $self->resolver_class;
+ Class::MOP::load_class($class);
+ return $class->new($self->resolver_config);
+ },
+);
+
+# FIXME This method is a gross hack.
+#
+# We need to work out what types of content mangles we have for various things based on hit type
+# file name and mime type, and perform the appropriate bits..
+
+# We need to support multiple languages, and we also want to be able to do HTMLizing (for e.g. Pod)
+
+sub process {
+ my ($self, $c) = @_;
+
+ my @steps = $self->resolve({ filename => $c->stash->{filename} });
+ my @css = map { $_->[1]->{css} } grep { exists $_->[1] && exists $_->[1]->{css} && defined $_->[1]->{css} && length $_->[1]->{css} } @steps;
+ $c->stash(
+ syntax_css => [ map { $c->uri_for('/static/css/syntax/' . $_ . '.css') } @css ],
+ mangled => scalar @steps,
+ );
+
+ if ($c->stash->{blobs} || $c->stash->{blob}) {
+ foreach my $step (@steps) {
+ for ($c->stash->{blobs} ? @{$c->stash->{blobs}} : $c->stash->{blob}) {
+ $_ = $c->view($step->[0])->render($c, $_, $step->[1]);
+ }
+ }
+ }
+}
+
+__PACKAGE__->meta->make_immutable;
--- /dev/null
+package Gitalist::URIStructure::Fragment::WithLog;
+use MooseX::MethodAttributes::Role;
+use namespace::autoclean;
+
+requires 'log';
+
+after log => sub {
+ my ($self, $c) = @_;
+ my $repository = $c->stash->{Repository};
+
+ my %logargs = (
+ sha1 => $c->stash->{Commit}->sha1, # $commit->sha1
+ count => 25, #Gitalist->config->{paging}{log} || 25,
+ );
+
+ my $page = $c->req->param('pg') || 0;
+ $logargs{skip} = abs $page * $logargs{count}
+ if $page;
+
+ $c->stash(
+ page => $page,
+ log_lines => [$repository->list_revs(%logargs)],
+ refs => $repository->references,
+ );
+};
+
+1;
--- /dev/null
+package Gitalist::URIStructure::Ref;
+use MooseX::MethodAttributes::Role;
+use Moose::Autobox;
+use namespace::autoclean;
+
+use Gitalist::Git::Types qw/SHA1/;
+
+requires 'base';
+
+with qw/
+ Gitalist::URIStructure::WithLog
+/;
+
+after 'base' => sub {
+ my ($self, $c) = @_;
+ confess("No repository in the stash")
+ unless $c->stash->{Repository};
+};
+
+sub find : Chained('base') PathPart('') CaptureArgs(1) {
+ my ($self, $c, $sha1part) = @_;
+ # FIXME - Should not be here!
+ $c->stash->{Commit} = $c->stash->{Repository}->get_object_or_head($sha1part)
+ or $c->detach('/error404', "Couldn't find a object for '$sha1part' in XXXX!");
+}
+
+sub diff : Chained('find') CaptureArgs(0) {}
+
+sub _set_diff_args {
+ my($self, $c, @rest) = @_;
+
+ # FIXME - This ain't pretty
+ $c->stash(parent => shift @rest)
+ if @rest == 2
+ # Check that the single arg is unlikely to be a path.
+ or @rest && to_SHA1($rest[0]) && $c->stash->{Repository}->get_object_or_head($rest[0]);
+ $c->stash(filename => $rest[-1])
+ if @rest;
+}
+
+sub diff_fancy : Chained('diff') PathPart('') Args() {
+ my($self, $c, @rest) = @_;
+
+ $self->_set_diff_args($c, @rest);
+ }
+
+sub diff_plain : Chained('diff') PathPart('plain') Args() {
+ my($self, $c, $comparison, @rest) = @_;
+
+ $self->_set_diff_args($c, @rest);
+
+ $c->stash(no_wrapper => 1);
+ $c->response->content_type('text/plain; charset=utf-8');
+}
+
+sub commit : Chained('find') PathPart('commit') Args(0) {}
+
+sub file_commit_info : Chained('find') Does('FilenameArgs') Args() {}
+
+sub tree : Chained('find') Does('FilenameArgs') Args() {}
+
+sub find_blob : Action {
+ my ($self, $c) = @_;
+ my($repo, $object) = @{$c->{stash}}{qw(Repository Commit)};
+ # FIXME - Eugh!
+ my $h = $object->isa('Gitalist::Git::Object::Commit')
+ ? $repo->hash_by_path($object->sha1, $c->stash->{filename})
+ : $object->isa('Gitalist::Git::Object::Blob')
+ ? $object->sha1
+ : die "Unknown object type for '${\$object->sha1}'";
+ die "No file or sha1 provided."
+ unless $h;
+ $c->stash(blob => $repo->get_object($h)->content);
+}
+
+sub blob : Chained('find') Does('FilenameArgs') Args() {
+ my ($self, $c) = @_;
+ $c->forward('find_blob');
+}
+
+sub blame : Chained('find') Does('FilenameArgs') Args() {}
+
+sub history : Chained('find') Does('FilenameArgs') Args() {}
+
+1;
--- /dev/null
+package Gitalist::URIStructure::Repository;
+use MooseX::MethodAttributes::Role;
+use Try::Tiny qw/try catch/;
+use namespace::autoclean;
+
+requires 'base';
+
+with qw/
+ Gitalist::URIStructure::WithLog
+/;
+
+sub find : Chained('base') PathPart('') CaptureArgs(1) {
+ my ($self, $c, $repos_name) = @_;
+ # XXX FIXME - This should be in the repository fragment controller, and the repository
+ # controller should just check has_repository
+ try {
+ my $repos = $c->model()->get_repository($repos_name);
+ $c->stash(
+ Repository => $repos,
+ HEAD => $repos->head_hash,
+ );
+ }
+ catch {
+ $c->detach('/error_404');
+ };
+}
+
+before 'log' => sub {
+ my ($self, $c) = @_;
+ $c->stash->{Commit} = $c->stash->{Repository}->get_object($c->stash->{Repository}->head_hash);
+};
+
+sub object : Chained('find') PathPart('') Args(1) {
+ my ($self, $c, $sha1) = @_;
+
+ my $repo = $c->stash->{Repository};
+ my $obj = $c->stash->{Commit} = $repo->get_object($sha1);
+ my($act) = (ref($obj) || '') =~ /::(\w+)$/;
+
+ $c->res->redirect($c->uri_for_action("/ref/\L$act", [$repo->name, $obj->sha1]));
+ $c->res->status(301);
+
+}
+
+sub summary : Chained('find') PathPart('') Args(0) {}
+
+sub heads : Chained('find') Args(0) {}
+
+sub tags : Chained('find') Args(0) {}
+
+1;
--- /dev/null
+package Gitalist::URIStructure::WithLog;
+use MooseX::MethodAttributes::Role;
+use namespace::autoclean;
+
+sub log : Chained('find') PathPart('') CaptureArgs(0) {}
+
+sub shortlog : Chained('log') Args(0) {}
+
+sub longlog : Chained('log') PathPart('log') Args(0) {}
+
+1;
\ No newline at end of file
return $age_str;
}
+sub is_binary {
+ # Crappy heuristic - does the first line or so look printable?
+ return $_[0] !~ /^[[:print:]]+$ (?: \s ^[[:print:]]+$ )?/mx;
+}
+
1;
__END__
=head2 age_string
-Turns an integer number of seconds into a string..
+Turns an integer number of seconds into a string.
+
+=head2 is_binary
+
+Check whether a string is binary according to C<-B>.
=head1 AUTHORS
package Gitalist::View::Default;
use Moose;
+use Moose::Autobox;
use namespace::autoclean;
extends 'Catalyst::View::TT';
+with 'Catalyst::View::Component::SubInclude';
use Template::Plugin::Cycle;
__PACKAGE__->config(
TEMPLATE_EXTENSION => '.tt2',
- WRAPPER => 'default.tt2',
+ WRAPPER => 'wrapper.tt2',
+ subinclude_plugin => 'SubRequest',
);
+use Template::Stash;
+
+# define list method to flatten arrayrefs
+$Template::Stash::LIST_OPS->{ to_path } = sub {
+ my $path = join('%2F', shift->flatten, @_);
+ $path =~ s{/}{%2F}g;
+ return $path;
+};
+
__PACKAGE__->meta->make_immutable(inline_constructor => 0);
__END__
use HTML::Entities qw(encode_entities);
-# What should be done, but isn't currently:
-#
-# broquaint> Another Cat question - if I want to have arbitrary things highlighted is pushing things through a View at all costs terribly wrong?
-# broquaint> e.g modifying this slightly to highlight anything (or arrays of anything) http://github.com/broquaint/Gitalist/blob/a7cc1ede5f9729465bb53da9c3a8b300a3aa8a0a/lib/Gitalist/View/SyntaxHighlight.pm
-# t0m> no, that's totally fine.. I'd tend to push the rendering logic into a model, so you end up doing something like: $c->model('SyntaxDriver')->highlight_all($stuff, $c->view('SyntaxHighlight'));
-# broquaint> I'm thinking it's a bad idea because the Controller needs to munge data such that the View knows what to do
-# broquaint> You just blew my mind ;)
-# t0m> ^^ That works _much_ better if you split up your view methods into process & render..
-# t0m> ala TT..
-# t0m> i.e. I'd have 'highlight this scalar' as the ->render method in the view..
-# t0m> And then the 'default' thing (i.e. process method) will do that and shove the output in the body..
-# t0m> but then you can write foreach my $thing (@things) { push(@highlighted_things, $c->view('SyntaxHighlight')->render($thing)); }
-# t0m> and then I'd move that ^^ loop down into a model which actually knows about / abstracts walking the data structures concerned..
-# t0m> But splitting render and process is the most important bit.. :) Otherwise you need to jump through hoops to render things that don't fit 'nicely' into the bits of stash / body that the view uses by 'default'
-# t0m> I wouldn't kill you for putting the structure walking code in the view given you're walking simple arrays / hashes.. It becomes more important if you have a more complex visitor..
-# t0m> (I use Visitor in the design patterns sense)
-# t0m> As the visitor is responsible for walking the structure, delegating to the ->render call in the view which is responsible for actually mangling the content..
-
sub process {
my($self, $c) = @_;
- for($c->stash->{blobs} ? @{$c->stash->{blobs}} : $c->stash->{blob}) {
- $_ = $self->highlight($c->stash->{language} => $_);
- }
-
- $c->forward('View::Default');
+ $c->res->body($self->render($c, $c->res->body, $c->stash));
}
-# XXX This takes for freakin' ever on big merges. A cache may be needed.
-sub highlight {
- my($self, $lang, $blob) = @_;
+sub render {
+ my ($self, $c, $blob, $args) = @_;
+
+ my $lang = $args->{language};
my $ret;
if($lang) {
+++ /dev/null
-[%- sha1 = sha1 || HEAD -%]
-<span class='chroma-hash'>[%-
- hptr = 0;
- WHILE hptr < sha1.length - 6;
- sha1part = sha1.substr(hptr, 6);
- "<span style='border-bottom: solid 4px #" _ sha1part _ ";'>" _ sha1part _ "</span>";
- hptr = hptr + 6;
- END;
--%]</span>
[% INCLUDE inc/syntax_highlight_css.tt2 %]
+
+<h2>Differences</h2>
+
+<div class="differences">
+
[% FOREACH item IN diff %]
-<div class='diff-head'>
- diff --git
- <a href='[% c.uri_for("blob", {h=item.src, f=item.file}) %]'>[% item.a %]</a>
- <a href='[% c.uri_for("blob", {h=item.dst, f=item.file}) %]'>[% item.b %]</a>
+
+<h4 id="diff[% loop.count %]" class='diff-head'>diff --git [%# FIXME %]
+ [% IF !item.src.match('^0+$') %]
+ <a href='[% c.uri_for_action("/ref/blob", [Repository.name, item.src]) %]' title="Blob">[% item.a %]</a>
+ [% ELSE %]
+ [% item.a %]
+ [% END %]
+ [% IF !item.dst.match('^0+$') %]
+ <a href='[% c.uri_for_action("/ref/blob", [Repository.name, item.dst]) %]' title="Blob">[% item.b %]</a>
+ [% ELSE %]
+ [% item.b %]
+ [% END %]
+</h4>
+
+
+<div class='diff-patch'>
+ <pre>[% blobs.${loop.index} %]</pre>
</div>
+
<div class='diff-index'>
- [% item.index %]
-</div>
-<div class='diff-patch'>
- <pre>[% blobs.${loop.index} %]</pre>
+ [% item.index.replace("index","<b>Index</b>") %]
</div>
+
[% END %]
+
+</div>
\ No newline at end of file
+<h2>[% diff_tree.size %] file[% "s" IF diff_tree.size > 1 %] in this diff <span>([%- Commit.sha1 || HEAD -%])</span></h2>
+
<table class='diff-tree listing'>
<thead>
<tr>
- <th>file</th>
- <th>status</th>
- <th>actions</th>
+ <th>File</th>
+ <th>Status</th>
+ <th>Actions</th>
</tr>
</thead>
- <tfoot>
- <tr>
- <td>file</td>
- <td>status</td>
- <td>actions</td>
- </tr>
- </tfoot>
<tbody>
[% FOREACH line IN diff_tree -%]
<tr>
<td class='file-name'>
- [% line.file %]
+ <a href="#diff[% loop.count %]">[% line.file %]</a>
</td>
<td class='status'>
[%
%]
</td>
<td class='action-list'>
- [% IF !line.is_new %]<a href="[% c.uri_for("blobdiff", {hp=commit.parent_sha1, h=commit.sha1, f=line.file}) %]">diff</a>[% END %]
- <a href="[% c.uri_for("blob", {h=line.sha1, hb=commit.sha1, f=line.file}) %]">blob</a>
- [% IF !line.is_new %]<a href="[% c.uri_for("shortlog", {hb=commit.sha1, f=line.file}) %]">history</a>[% END %]
+ [% IF !line.is_new %]<a href="[% c.uri_for_action("/ref/diff_fancy", [Repository.name, Commit.sha1], line.file.to_path) %]" title="Difference" class="button diff">diff</a>[% END %]
+ [% IF !line.is_new %]<a href="[% c.uri_for_action("/ref/history", [Repository.name, Commit.sha1], line.file.to_path) %]" title="History (Short Log)" class="button history">history</a>[% END %]
+ <a href="[% c.uri_for_action("/ref/blob", [Repository.name, Commit.sha1], line.file.to_path) %]" title="Blob" class="button blob">blob</a>
</td>
</tr>
[% END %]
<link
rel="alternate"
title="[% Repository.name %] - [% title %] Atom feed"
- href="[% c.uri_for('atom') %]"
+ href="[% c.uri_for_action('/repository/atom', [Repository.name]) %]"
type="application/atom+xml"
>
<link
rel="alternate"
title="[% Repository.name %] - [% title %] RSS feed"
- href="[% c.uri_for('rss') %]"
+ href="[% c.uri_for_action('/repository/rss', [Repository.name]) %]"
type="application/rss+xml"
>
[% ELSE %]
title="[% c.config.sitename %] Git repositories list"
href="[% c.uri_for('repository_index') %]"
type="text/plain; charset=utf-8"
- >
+ >
<link
rel="alternate"
title="[% c.config.sitename %] Git repositories feeds"
- href="[% c.uri_for('opml') %]"
+ href="[% c.uri_for_action('/opml/opml') %]"
type="text/x-opml"
>
[% END %]
+++ /dev/null
-<table class='[% action %] listing'>
- <thead>
- <tr>
- <th>HEAD</th>
- <th>age</th>
- <th>branch</th>
- <th>actions</th>
- </tr>
- </thead>
- <tfoot>
- <tr>
- <td>HEAD</td>
- <td>age</td>
- <td>branch</td>
- <td>actions</td>
- </tr>
- </tfoot>
-
- <tbody>
- [% FOREACH head IN heads %]
- <tr>
- <td class='sha1' title='[% head.sha1 %]'>[% INCLUDE '_chroma_hash.tt2' sha1 = head.sha1.substr(0,7) %]</td>
- <td class='time-since' title='[% head.last_change %]'>[% time_since(head.last_change) %]</td>
- <td class='head[% head.sha1 == HEAD ? ' current' : '' %]'>[% head.name %]</td>
- <td class='action-list'>
- <a href="[% c.uri_for("shortlog", {h='refs/heads/' _ head.name}) %]">shortlog</a>
- <a href="[% c.uri_for("log", {h='refs/heads/' _ head.name}) %]">log</a>
- <a href="[% c.uri_for("tree", {h='refs/heads/' _ head.name, hb=head.name}) %]">tree</a>
- </td>
- </tr>
- [% END %]
- </tbody>
-</table>
+++ /dev/null
-<table class='history listing'>
- <thead>
- <tr>
- <th>sha1</th>
- <th>time</th>
- <th>author</th>
- <th>message</th>
- <th>actions</th>
- </tr>
- </thead>
-
- <tfoot>
- <tr>
- <td>sha1</td>
- <td>time</td>
- <td>author</td>
- <td>message</td>
- <td>actions</td>
- </tr>
- </tfoot>
-
- <tbody>
- [% FOREACH line IN log_lines %]
- <tr>
- <td class='sha1' title='[% line.sha1 %]'>[% INCLUDE '_chroma_hash.tt2' sha1 = line.sha1.substr(0, 7) %]</td>
- <td class='time-since' title='[% line.authored_time %]'>[% time_since(line.authored_time) %]</td>
- <td class='author'>[% line.author.name | html %]</td>
- <td>
- [% short_cmt(line.comment) | html %]
- [% INCLUDE '_refs.tt2' object = line.0 %]
- </td>
- <td class='action-list'>
- [% IF filetype == 'tree' %]
- <a href="[% c.uri_for("tree", {h=line.sha1, hb=line.sha1}) %]">tree</a>
- [% ELSIF filetype == 'blob' %]
- <a href="[% c.uri_for("blob", {hb=line.sha1, f=filename}) %]">blob</a>
- [% END %]
- <a href="[% c.uri_for("commitdiff", {h=line.sha1}) %]">commitdiff</a>
- [% IF filetype == 'blob' %]
- <a href="[% c.uri_for("blobdiff", {hb="HEAD", hpb=line.sha1, f=filename}) %]">diff to current</a>
- [% END %]
- </td>
- </tr>
- [% END %]
- </tbody>
-</table>
<div class='pager'>
- <a href='[% c.uri_for(action, {h=HEAD}) %]'>HEAD</a> §
+ <a href='[% c.uri_for_action('/' _ c.action, [Repository.name, 'HEAD']) %]'>HEAD</a> §
[% IF log_lines.first.sha1 != commit.sha1 %]
- <a href='[% c.request.uri_with(pg => page - 1) %]'>« prev</a>
+ <a href='[% c.request.uri_with(pg => (page||0) - 1) %]'>« prev</a>
[% END %]
[% IF log_lines.size == 50 %]
- <a href='[% c.request.uri_with(pg => page + 1) %]'>next »</a>
+ <a href='[% c.request.uri_with(pg => (page||0) + 1) %]'>next »</a>
[% END %]
</div>
<span class='refs'>
[% FOREACH ref IN refs.${object.sha1} %]
<span class='[% ref.search('^remotes/') ? 'remote' : 'head' %]'>
- <a href='[% c.uri_for("shortlog", {h='refs/' _ ref}) %]'>[% ref.replace('^(remote|head)s/', '') %]</a>
+ <a href='[% c.uri_for_action("/ref/shortlog", [Repository.name, object.sha1]) %]'>[% ref.replace('^(remote|head)s/', '') %]</a>
</span>
[% END %]
</span>
+++ /dev/null
-<table class='shortlog listing'>
- <thead>
- <tr>
- <th>sha1</th>
- <th>time</th>
- <th>author</th>
- <th>message</th>
- <th>actions</th>
- </tr>
- </thead>
-
- <tfoot>
- <tr>
- <td>sha1</td>
- <td>time</td>
- <td>author</td>
- <td>message</td>
- <td>actions</td>
- </tr>
- </tfoot>
-
- <tbody>
- [% FOREACH line IN log_lines %]
- <tr>
- <td class='sha1' title='[% line.sha1 %]'>[% INCLUDE '_chroma_hash.tt2' sha1 = line.sha1.substr(0, 7) %]</td>
- <td class='time-since' title='[% line.authored_time %]'>[% time_since(line.authored_time) %]</td>
- <td class='author'>[% line.author.name | html %]</td>
- <td>
- [% short_cmt(line.comment) | html %]
- [% INCLUDE '_refs.tt2' object = line %]
- </td>
- <td class='action-list'>
- <a href="[% c.uri_for("commit", {h=line.sha1}) %]">commit</a>
- <a href="[% c.uri_for("commitdiff", {h=line.sha1}) %]">commitdiff</a>
- <a href="[% c.uri_for("tree", {h=line.sha1, hb=line.sha1}) %]">tree</a>
- </td>
- </tr>
- [% END %]
- </tbody>
-</table>
+++ /dev/null
-<table class='tree listing'>
- <thead>
- <tr>
- <th>mode</th>
- <th>file</th>
- <th>actions</th>
- </tr>
- </thead>
- <tfoot>
- <tr>
- <td>mode</td>
- <td>file</td>
- <td>actions</td>
- </tr>
- </tfoot>
-
- <tbody>
- [% FOREACH item IN tree_list %]
- <tr>
- <td class='file-mode'>[% item.modestr %]</td>
- [% theact = item.type == 'tree' ? 'tree' : 'blob' -%]
- [% fullpath = path ? path _ '/' _ item.file : item.file %]
- <td class='file-name'>
- <a href="[% c.uri_for(theact, {h=item.sha1, hb=commit.sha1, f=fullpath}) %]">[% item.file %]</a>
- </td>
- <td class='action-list'>
- <a href="[% c.uri_for(theact, {h=item.sha1, hb=commit.sha1, f=fullpath}) %]">[% theact %]</a>
- [% IF item.type == 'blob' %]
- <a href="[% c.uri_for('blame', {h=commit.sha1, hb=commit.sha1, f=fullpath}) %]">blame</a>
- [% END %]
- <a href="[% c.uri_for('history', {h=item.sha1, hb=commit.sha1, f=fullpath}) %]">history</a>
- [% IF item.type == 'blob' %]
- <a href="[% c.uri_for('raw', {hb=commit.sha1, f=fullpath}) %]">raw</a>
- [% END %]
- </td>
- </tr>
- [% END %]
- </tbody>
-</table>
+++ /dev/null
-[% PROCESS 'nav/actions.tt2' object = head %]
-[% INCLUDE inc/syntax_highlight_css.tt2 %]
-
-<div class='content'>
-
-[% IF object.type == 'commit' %]
-<div class='commit-message'>[% short_cmt(head.comment) %]</div>
-[% END %]
-
-[% INCLUDE 'nav/path.tt2' %]
-
-<div id='blame'>
-<table>
- <thead>
- <tr>
- <th>author</th>
- <th>date</th>
- <th>sha1</th>
- <th></th>
- <th class='data'>data</th>
- </tr>
- </thead>
-
- <tfoot>
- <tr>
- <td>author</td>
- <td>date</td>
- <td>sha1</td>
- <td></td>
- <td class='data'>data</td>
- </tr>
- </tfoot>
-
- <tbody>
- [% blame_lines = blob.split("\n") %]
- [% FOR info IN blame %]
- <tr class=''>
- [%-
- linecolour = info.commit.sha1.substr(0,6);
- IF info.commit.sha1 != lastsha1;
- styleinfo = " style='border-top: solid 3px #" _ linecolour _ ";'"; -%]
- <td nowrap class='author'[% styleinfo %]>[% info.commit.author %]</td>
- <td nowrap class='date'[% styleinfo %]>[% info.commit.author_dt.ymd %]</td>
- <td nowrap class='commit-info chroma-hash'[% styleinfo %]><a title="[% info.commit.author %] on [% info.commit.author_dt %]" href='[% c.uri_for('commit', {h=info.commit.sha1}) %]'>[% linecolour %]</td>
- [%- ELSE -%]
- <td nowrap class='author'></td>
- <td nowrap class='date'></td>
- <td nowrap class='commit-info'></td>
- [%- END -%]
- <td nowrap class='lineno' id='l[% info.meta.lineno %]' style='border-right: solid 3px #[% linecolour %]; border-left: solid 3px #[% linecolour %];'><tt><a href='[% c.uri_for('blame', {h=info.commit.sha1,f=filename}) %]#l[% info.meta.orig_lineno %]'>[% info.meta.lineno %]</a></tt></td>
- <td nowrap class='data'><pre>[% blame_lines.${loop.index} %]</pre></td>
- [% lastsha1 = info.commit.sha1 %]
- </tr>
- [% END %]
- </tbody>
-</table>
-</div>
-
-</div>
+++ /dev/null
-[% INCLUDE inc/syntax_highlight_css.tt2 %]
-[% PROCESS 'nav/actions.tt2' object = head %]
-
-<div class='content'>
- [% IF object.type == 'commit' %]
- <div class='commit-message'>
- [% short_cmt(head.comment) %]
- </div>
- [% END %]
- [% INCLUDE 'nav/path.tt2' %]
- <div>
- <pre class='blob'>[% blob %]</pre>
- </div>
-</div>
+++ /dev/null
-[% PROCESS 'nav/actions.tt2' object = commit %]
-
-<div class='content'>
- <div class='commit-message'>
- [% short_cmt(commit.comment) | html %] ...
- </div>
-
- [% INCLUDE '_diff.tt2' %]
-</div>
+++ /dev/null
-[%- INCLUDE '_diff_plain.tt2' -%]
+++ /dev/null
-[% INCLUDE 'nav/actions.tt2' object = commit %]
-
-<div class='content'>
- <div class='commit-message'>
- [%
- short_cmt(commit.comment) | html;
- INCLUDE '_refs.tt2' object = commit;
- %]
- </div>
- <!-- [% USE dumper; dumper.dump(commit.parents) %] -->
- <dl class='commit-info'>
- <dt>author</dt>
- <dd>[% commit.author.name | html %] <[% commit.author.email %]><br/>
- [% commit.authored_time %]</dd>
- <dt>committer</dt>
- <dd>[% commit.committer.name %] <[% commit.committer.email %]><br/>
- [% commit.committed_time %]</dd>
- <dt>commit</dt>
- <dd>[% commit.sha1 %]</dd>
- <dt>tree</dt>
- <dd>[% commit.tree_sha1 %]
- <span class='action-list'><a href="[% c.uri_for("tree", {h=commit.tree_sha1, hb=commit.sha1}) %]">tree</a></span>
- </dd>
- [% FOREACH parent IN commit.parents %]
- <dt>parent</dt>
- <dd>[% parent.sha1 %]
- <span class='action-list'>
- <a href="[% c.uri_for("commit", {h=parent.sha1}) %]">commit</a>
- <a href="[% c.uri_for("commitdiff", {hp=parent.sha1, h=commit.sha1}) %]">diff</a>
- </span>
- </dd>
- [% END %]
- </dl>
-
- <pre class='commit-message'>[% commit.comment | html%]</pre>
-
- [%
- # In the case of merge commits there will be no diff tree.
- IF diff_tree.size > 0;
- INCLUDE '_diff_tree.tt2';
- END;
- %]
-</div>
+++ /dev/null
-[% PROCESS 'nav/actions.tt2' object = commit %]
-
-<div class='content'>
- <div class='commit-message'>
- [% # XXX Wah, stuff like this doesn't work because end() isn't called as we forward to View::SyntaxHighlight
- short_cmt(commit.comment) | html %]
- </div>
-
- <div class='author'>
- [% commit.author.name | html %] [[% commit.authored_time %]]
- </div>
-
-
- [%
- # In the case of merge commits there will be no diff tree.
- IF diff_tree.size > 0;
- INCLUDE '_diff_tree.tt2';
- END;
- IF diff.size > 0;
- INCLUDE '_diff.tt2';
- ELSE
- %]
- <div class='no-difference'>
- [%
- IF commit.parents > 1;
- 'Trivial merge';
- ELSE;
- 'No differences found';
- END;
- %]
- </div>
- [% END %]
-</div>
+++ /dev/null
-[%- INCLUDE '_diff_plain.tt2' -%]
+++ /dev/null
-[%- IF no_wrapper || template.name.match('\.(css|js|txt)'); content; ELSE; -%]
-<!DOCTYPE html>
-<html lang="en">
-<head>
- <!-- git core binaries version [% git_version %] -->
- <meta charset="utf-8">
- <meta name="generator" content="gitweb/[% version %] git/[% git_version %][% mod_perl_version %]">
- <meta name="robots" content="index, nofollow">
- <title>[%-
- title = BLOCK;
- c.config.sitename;
- IF Repository; ' - ' _ Repository.name | html; END;
- IF action; ' / ' _ action; END;
- IF filename; ' - ' _ filename | html; END;
- IF action && action == 'tree'; '/'; END;
- END;
- title;
- -%] (Gitalist)</title>
- [% INCLUDE '_header_feeds.tt2' %]
- <link rel="stylesheet" href="[% c.uri_for('/static/css/blueprint/screen.css') %]" type="text/css" media="screen, projection">
- <link rel="stylesheet" href="[% c.uri_for('/static/css/blueprint/print.css') %]" type="text/css" media="print">
- <!--[if lt IE 8]>
- <link rel="stylesheet" href="[% c.uri_for('/static/css/blueprint/ie.css') %]" type="text/css" media="screen, projection">
- <![endif]-->
- <link rel="stylesheet" type="text/css" href="[% c.uri_for('/static/css/site.css') %]">
- <link rel="shortcut icon" href="[% c.uri_for('git-favicon.png') %]" type="image/png">
-</head>
-
-<body>
-
-<div id='the-container'>
-
-[% site_header %]
-
-<div id="page-header">
- <a title="git homepage" href="http://git-scm.org">
- <img src="[% c.uri_for('/logo.png') %]" alt="git" class="logo">
- </a>
- <a href="[% c.uri_for('/', {p=''}) %]">A Gitalist</a>
- [%- IF Repository %]
- / <a href="[% c.uri_for('summary') %]">[% Repository.name %]</a>
- [% IF action; " / " _ action; END;
- END %]
-[%
- IF Repository;
- INCLUDE 'nav/search.tt2';
- END;
-# / git_header_html
-%]
-</div>
-
-<div id='body'>
-[%
- IF action;
- SET actmpl = action _ ".tt2";
- INCLUDE $actmpl;
- ELSE;
- # The output of gitweb.cgi is injected at this point.
- content;
- END;
-%]
-</div>
-
-<div id="page-footer">
-[% IF Repository %]
- [% Repository.description | html %]
-[% END %]
-[% INCLUDE '_footer_feeds.tt2' %]
-</div>
-
-</div>
-
-</body>
-</html>
-[%- END -%]
--- /dev/null
+<tbody>
+[% FOR p IN repositories %]
+ [%- repos_link = c.uri_for_action('/repository/summary', [p.name]) -%]
+<tr [% "class='invert'" IF loop.count % 2 %]>
+ <td>[% loop.count %]</td>
+ <td><a href="[% repos_link %]/shortlog"><strong>[% p.name %]</strong></a></td>
+ <td class="description"><div title="[% p.description %]">[% abridged_description(p.description) IF p.description != "Unnamed repository; edit this file to name it for gitweb." %]</div></td>
+ <td class="time-since">[% time_since(p.last_change) %]</td>
+ <td>[% p.owner %]</td>
+ <td class="action-list">
+ <a href="[% c.uri_for_action('/repository/shortlog', [p.name]) %]" title="Short log" class="button shortlog">short log</a>
+ <a href="[% c.uri_for_action('/repository/longlog', [p.name]) %]" title="Long log" class="button longlog">long log</a>
+ <a href="[% c.uri_for_action('/ref/tree', [p.name, 'HEAD']) %]" title="Tree" class="button tree">tree</a>
+ </td>
+</tr>
+[% END %]
+</tbody>
--- /dev/null
+[% blame_lines = blob.split("\n") %]
+ [% FOR info IN blame %]
+ <tr class=''>
+ [%-
+ linecolour = info.commit.sha1.substr(0,6);
+ IF info.commit.sha1 != lastsha1;
+ styleinfo = " style='border-top: solid 3px #" _ linecolour _ ";'"; -%]
+ <td nowrap class='author'[% styleinfo %]>[% info.commit.author %]</td>
+ <td nowrap class='date'[% styleinfo %]>[% info.commit.author_dt.ymd %]</td>
+ <td nowrap class='sha1 commit-info chroma-hash'[% styleinfo %]><a title="[% info.commit.author %] on [% info.commit.author_dt %]" href='[% c.uri_for_action('/ref/commit', [Repository.name, info.commit.sha1]) %]'>[% INCLUDE 'inc/chroma_hash.tt2' sha1 = info.commit.sha1.substr(0, 7) %]</a>
+[%# linecolour %]</td>
+ [%- ELSE -%]
+ <td nowrap class='author'></td>
+ <td nowrap class='date'></td>
+ <td nowrap class='commit-info'></td>
+ [%- END -%]
+ <td nowrap class='lineno' id='l[% info.meta.lineno %]' style='border-right: solid 3px #[% linecolour %]; border-left: solid 3px #[% linecolour %];'><tt><a href='[% c.uri_for_action('/ref/blame', [Repository.name, info.commit.sha1], filename.to_path ) %]#l[% info.meta.orig_lineno %]'>[% info.meta.lineno %]</a></tt></td>
+ <td nowrap class='data'><pre>[% blame_lines.${loop.index} | html %]</pre></td>
+ [% lastsha1 = info.commit.sha1 %]
+ </tr>
+ [% END %]
--- /dev/null
+[%- IF is_image -%]
+<div class='blob'><img src="[% c.uri_for_action('/ref/raw', c.req.captures, filename) %]" title="[% filename %]"></div>
+[%- ELSIF is_binary -%]
+<div class='blob'>This is a binary file which won't render natively on the web, but you can get it here all the same: <a href="[% c.uri_for_action('/ref/raw', c.req.captures, filename) %]" title="[% filename %]">[% filename %]</a></div>
+[%- ELSE -%]
+[%- INCLUDE inc/syntax_highlight_css.tt2 -%]
+<pre class='blob'>[% IF mangled; blob; ELSE; blob | html; END; %]</pre>
+[%- END -%]
--- /dev/null
+<table class="listing">
+<thead>
+<tr>
+ <th>ID (sha1)</th>
+ <th>Last change</th>
+ <th>Message</th>
+ <th>By</th>
+ <th>Role</th>
+</tr>
+</thead>
+<tbody>
+<tr class="invert">
+ <td class='sha1' title='[% Commit.sha1 %]'>[% INCLUDE 'inc/chroma_hash.tt2' sha1 = Commit.sha1.substr(0, 7) %]</td>
+ <td class='time-since'>[% time_since(Commit.authored_time) %]</td>
+ <td rowspan="2">
+ [% Commit.comment | html%]
+ [%
+
+ INCLUDE '_refs.tt2' object = commit;
+ %]</td>
+ <td class='author'><a href="mailto:[% Commit.author.email %]" title="Email"><img style="float: left; padding-right: 10px" src="[% uri_for_gravatar(Commit.committer.email, 21) %]">[% Commit.author.name | html %]</a></td>
+ <td class='action-list'>Author</td>
+</tr>
+<tr class="invert">
+ <td></td>
+ <td class='time-since'>[% time_since(Commit.committed_time) %]</td>
+ <!-- spanned -->
+ <td class='author'><a href="mailto:[% Commit.committer.email %]" title="Email"><img style="float: left; padding-right: 10px" src="[% uri_for_gravatar(Commit.committer.email, 21) %]">[% Commit.committer.name %]</a></td>
+ <td class='action-list'>Committer</td>
+</tr>
+</tbody>
+</table>
+ <!-- [% USE dumper; dumper.dump(commit.parents) %] -->
+
+
+
+<table class="listing summary">
+ <tr>
+ <td class='sha1'>[% INCLUDE 'inc/chroma_hash.tt2' sha1 = Commit.sha1.substr(0, 7), hide_sha1_output = 1 %] <div class="sha1_label">Commit</div></td>
+ <td>[% Commit.sha1 %]</td>
+ <td class='action-list'><a href="[% c.uri_for_action('/ref/diff_fancy', [Repository.name, Commit.sha1]) %]" title="Difference" class="button diff">diff</a></td>
+ </tr>
+ <tr>
+ <td class='sha1'>[% INCLUDE 'inc/chroma_hash.tt2' sha1 = Commit.tree_sha1.substr(0, 7), hide_sha1_output = 1 %] <div class="sha1_label">Tree</div></td>
+ <td>[% Commit.tree_sha1 %]</td>
+ <td class='action-list'><a href="[% c.uri_for_action("/ref/tree", c.req.captures) %]" title="Tree" class="button tree">tree</a></td>
+ </tr>
+ [% FOREACH parent IN Commit.parents %]
+ <tr>
+ <td class='sha1'>[% INCLUDE 'inc/chroma_hash.tt2' sha1 = parent.sha1.substr(0, 7), hide_sha1_output = 1 %] <div class="sha1_label">Parent</div></td>
+ <td>[% parent.sha1 %]</td>
+ <td class='action-list'>
+ <a href="[% c.uri_for_action('/ref/commit', [Repository.name, parent.sha1]) %]" title="Commit" class="button commit">commit</a>
+ <a href="[% c.uri_for_action('/ref/diff_fancy', [Repository.name, parent.sha1]) %]" title="Difference" class="button diff">diff</a>
+ </td>
+ </tr>
+[% END %]
+</table>
+
+
+
+ [%
+ # In the case of merge commits there will be no diff tree.
+ IF diff_tree && diff_tree.size > 0;
+ INCLUDE '_diff_tree.tt2';
+ END;
+ %]
--- /dev/null
+[%
+ # In the case of merge commits there will be no diff tree.
+ IF (diff_tree.size||0) > 0;
+ INCLUDE '_diff_tree.tt2';
+ END;
+ IF (diff.size||0) > 0;
+ INCLUDE '_diff.tt2';
+ ELSE
+ %]
+ <p class='msg'>
+ [%
+ IF commit && commit.parents > 1;
+ 'Trivial merge';
+ ELSE;
+ 'No differences found';
+ END;
+ %]
+ </p>
+ [% END %]
+
--- /dev/null
+[%- FOREACH item IN diff -%]
+diff --git [% item.a _ ' ' _ item.b %]
+[% item.index %]
+[% blobs.${loop.index} %]
+[%- END -%]
--- /dev/null
+[% BLOCK history_table_headfoot %]
+[% SET cell = type == 'head' ? 'th' : 'td' %]
+<tr>
+<[% cell %] colspan="2"><a href="" class='compare-link'>Compare</a></[% cell %]>
+ <[% cell %]>sha1</[% cell %]>
+ <[% cell %]>time</[% cell %]>
+ <[% cell %]>message</[% cell %]>
+ <[% cell %]>author</[% cell %]>
+ <[% cell %]>actions</[% cell %]>
+</tr>
+[% END %]
+<form id="compare-form">
+ <table class='listing'>
+ <thead>[% PROCESS history_table_headfoot type = 'head' %]</thead
+
+ <tbody>
+ [% FOREACH line IN log_lines %]
+ <tr [% "class='invert'" IF loop.count % 2 %]>
+ <td><input type="radio" name="sha1_a" value="[% line.sha1 %]"[% " checked" IF loop.count == 2 %] /></td>
+ <td><input type="radio" name="sha1_b" value="[% line.sha1 %]"[% " checked" IF loop.count == 1 %]/></td>
+ <td class='sha1' title='[% line.sha1 %]'>[% INCLUDE 'inc/chroma_hash.tt2' sha1 = line.sha1.substr(0, 7) %]</td>
+ <td class='time-since' title='[% line.authored_time %]'>[% time_since(line.authored_time) %]</td>
+
+ <td>
+ [% short_cmt(line.comment) | html %]
+ [% INCLUDE '_refs.tt2' object = line.0 %]
+ </td>
+ <td class='author'>[% line.author.name | html %]</td>
+ <td class='action-list'>
+ [% IF filetype == 'tree' %]
+ <a href="[% c.uri_for_action("/ref/tree", [Repository.name, line.sha1], filename) %]" title="Blob" class="button blob">blob</a>
+ [% ELSIF filetype == 'blob' %]
+ <a href="[% c.uri_for_action("/ref/blob", [Repository.name, line.sha1], filename) %]" title="Blob" class="button blob">blob</a>
+ [% END %]
+ <a href="[% c.uri_for_action("/ref/diff_fancy", [Repository.name, line.sha1]) %]" title="Commit diff" class="button diff">commitdiff</a>
+ [% IF filetype == 'blob' %]
+ <a href="[% c.uri_for_action("/ref/diff_fancy", [Repository.name, line.sha1], 'HEAD', filename) %]" title="Diff to current" class="button diffcurrent">diff to current</a>
+ [% END %]
+ </td>
+ </tr>
+ [% END %]
+ <tr>
+ <td colspan="2"><a href="" class='compare-link'>Compare</a></td>
+ <td colspan="5"></td>
+</tr>
+ </tbody>
+ </table>
+</form>
+
+<span id='compare-path' class='js-data'>[% filename %]</span>
+<span id="diff-uri" class='js-data'>[% c.uri_for_action('/ref/diff_fancy', [Repository.name, 'HEAD']) %]</span>
+
+[% INCLUDE 'inc/log_pager.tt2' %]
--- /dev/null
+[% PROCESS 'fragment/repository/longlog.tt2' %]
--- /dev/null
+[% PROCESS 'fragment/repository/shortlog.tt2' %]
--- /dev/null
+[% BLOCK tree_table_headfoot %]
+[% SET cell = type == 'head' ? 'th' : 'td' %]
+ <tr>
+ <[% cell %]>Mode</[% cell %]>
+ <[% cell %]>Folder / File</[% cell %]>
+ <[% cell %]>Actions</[% cell %]>
+ <[% cell %]>Message</[% cell %]>
+ </tr>
+[% END %]
+[%-
+ SET counter = 1;
+
+ # sort files and folders
+ SET tree_files = [];
+ SET tree_folders = [];
+ FOREACH item IN tree_list;
+ IF item.type == "blob";
+ tree_files.push(item);
+ ELSE;
+ tree_folders.push(item);
+ END;
+ END;
+%]
+
+[% BLOCK output_tree %]
+ [% FOREACH item IN tree_type.sort('file') %]
+ <tr [% "class='invert'" IF counter % 2 %]>
+ <td class='file-mode'>[% item.modestr %]</td>
+ [%-
+ action_type = item.type == 'tree' ? 'tree' : 'blob';
+ action_for_link = item.type == 'tree' ? '/ref/tree' : '/ref/blob';
+ blob_or_tree_link = c.uri_for_action(action_for_link, c.req.captures, c.req.args.to_path(item.file))
+ -%]
+ <td class="file-name"><a href="[% blob_or_tree_link %]" class="[% item.type == 'blob' ? 'file' : 'folder' %]">[% item.file %]</a></td>
+ <td class='action-list'>
+ <a href="[% blob_or_tree_link %]">[% theact %]</a>
+ [% IF item.type == 'blob' %]
+ <a href="[% c.uri_for_action('/ref/blob', c.req.captures, c.req.args.to_path(item.file)) %]" title="Blob" class="button blob">Blob</a>
+ <a href="[% c.uri_for_action('/ref/raw', c.req.captures, c.req.args.to_path(item.file)) %]" title="Raw" class="button raw">raw</a>
+ <a href="[% c.uri_for_action('/ref/blame', c.req.captures, c.req.args.to_path(item.file)) %]" title="Blame" class="button blame">blame</a>
+ [% END %]
+ <a href="[% c.uri_for_action('/ref/history', c.req.captures, c.req.args.to_path(item.file)) %]" title="History (Short log)" class="button shortlog">Short log</a>
+ </td>
+ <td class="message"><span class='js-data'>[% c.req.args.to_path(item.file) %]</span>Loading commit info ...</td>
+ </tr>
+ [% counter = counter + 1 %]
+ [% END %]
+[% END %]
+
+<table class="listing" id="commit-tree">
+<thead>[% PROCESS tree_table_headfoot type = 'head' %]</thead>
+<tbody>
+ [% INCLUDE output_tree tree_type => tree_folders %]
+ [% PROCESS output_tree tree_type => tree_files %]
+</tbody>
+</table>
+
+[%- # We use uri_for instead of uri_for_action as we *want* a /fragment URI in this case %]
+<span id='file_commit_info-uri' class='js-data'>[% c.uri_for('/fragment/' _ Repository.name _ '/' _ Commit.sha1 _ '/file_commit_info') %]</span>
+<span id='commit-uri' class='js-data'>[% c.uri_for_action('/ref/commit', [Repository.name, 'HEAD']) %]</span>
\ No newline at end of file
--- /dev/null
+[% BLOCK repository_heads_headfoot %]
+[% SET cell = type == 'head' ? 'th' : 'td' %]
+<tr class="header">
+ <[% cell %]>HEAD</[% cell %]>
+ <[% cell %]>Last change</[% cell %]>
+ <[% cell %]>Branch</[% cell %]>
+ <[% cell %]>Actions</[% cell %]>
+</tr>
+[% END %]
+
+<table class='[% action %] listing'>
+ <thead>[% PROCESS repository_heads_headfoot type = 'head' %]</thead>
+ <tbody>
+ [% FOREACH head IN heads %]
+ <tr>
+ <td class='sha1' title='[% head.sha1 %]'>[% INCLUDE 'inc/chroma_hash.tt2' sha1 = head.sha1.substr(0,7) %]</td>
+ <td class='time-since' title='[% head.last_change %]'>[% time_since(head.last_change) %]</td>
+ <td class='head[% head.sha1 == HEAD ? ' current' : '' %]'>[% head.name %]</td>
+ <td class='action-list'>[%# FIXME %]
+ <a href="[% c.uri_for_action('/ref/shortlog', [Repository.name, head.name]) %]" title="Short log" class="button shortlog">shortlog</a>
+ <a href="[% c.uri_for_action('/ref/longlog', [Repository.name, head.name]) %]" title="Long log" class="button longlog">log</a>
+ <a href="[% c.uri_for_action('/ref/tree', [Repository.name, head.name]) %]" title="Tree" class="button tree">tree</a>
+ </td>
+ </tr>
+ [% END %]
+ </tbody>
+</table>
--- /dev/null
+[% INCLUDE 'fragment/repository/shortlog.tt2' longlogformat = 1 %]
+
+
+<h2>Branches</h2>
+[% subinclude('/fragment/repository/heads', [Repository.name]) %]
--- /dev/null
+[% BLOCK shortlog_table_headfoot %]
+[% SET cell = type == 'head' ? 'th' : 'td' %]
+<tr>
+ <[% cell %] colspan="2"><a href="" class="compare-link">Compare</a></[% cell %]>
+ <[% cell %]>ID (sha1)</[% cell %]>
+ <[% cell %]>Last change</[% cell %]>
+ <[% cell %]>Message</[% cell %]>
+ <[% cell %]>By</[% cell %]>
+ <[% cell %]>Actions</[% cell %]>
+</tr>
+[% END %]
+
+<form id="compare-form">
+<table class='listing'>
+<thead>[% PROCESS shortlog_table_headfoot type = 'head' %]</thead>
+<tbody>
+ [% FOREACH line IN log_lines %]
+ <tr [% "class='invert'" IF loop.count % 2 %]>
+ <td><input type="radio" name="sha1_a" value="[% line.sha1 %]" [% "checked" IF loop.count == 1 %] /></td>
+ <td><input type="radio" name="sha1_b" value="[% line.sha1 %]" [% "checked" IF loop.count == 2 %]/></td>
+ <td class='sha1' title='[% line.sha1 %]'>[% INCLUDE 'inc/chroma_hash.tt2' sha1 = line.sha1.substr(0, 7) %]</td>
+ <td class='time-since' title='[% line.authored_time %]'>[% time_since(line.authored_time) %]</td>
+ <td>
+ [% IF longlogformat %]
+ [% message = line.comment | html; message.replace("\n", "<br/>") %]
+ [% ELSE %]
+ [% short_cmt(line.comment) | html %]
+ [% INCLUDE '_refs.tt2' object = line %]
+ [% END %]
+ </td>
+ <td class='author'><img src="[% uri_for_gravatar(line.author.email, 21) %]" />[% line.author.name | html %]</td>
+ <td class='action-list'>
+ <a href="[% c.uri_for_action("/ref/commit", [Repository.name, line.sha1]) %]" title="Commit details" class="button commit">commit</a>
+ <a href="[% c.uri_for_action("/ref/diff_fancy", [Repository.name, line.sha1]) %]" title="Commit difference" class="button diff">commitdiff</a>
+ <a href="[% c.uri_for_action("/ref/tree", [Repository.name, line.sha1]) %]" title="Tree" class="button tree">tree</a>
+ </td>
+</tr>
+[% END %]
+<tr>
+ <td colspan="2"><a href="" class="compare-link">Compare</a></td>
+ <td colspan="5"></td>
+</tr>
+</tbody>
+</table>
+</form
+
+<span id="diff-uri" class="js-data">[% c.uri_for_action('/ref/diff_fancy', [Repository.name, 'HEAD']) %]</span>
+
+[% INCLUDE 'inc/log_pager.tt2' %]
--- /dev/null
+<dl>
+ <dt>description</dt><dd>[% Repository.description %]</dd>
+ <dt>owner</dt><dd>[% Repository.owner %]</dd>
+ <dt>last change</dt><dd>[% time_since(Repository.last_change) %]</dd>
+</dl>
--- /dev/null
+[% INCLUDE 'fragment/repository/heads.tt2' heads = tags %]
+++ /dev/null
-body {
- font-family: sans-serif;
- font-size: small;
- border: solid #d9d8d1;
- border-width: 1px;
- margin: 10px;
- background-color: #ffffff;
- color: #000000;
-}
-
-a {
- color: #0000cc;
-}
-
-a:hover, a:visited, a:active {
- color: #880000;
-}
-
-span.cntrl {
- border: dashed #aaaaaa;
- border-width: 1px;
- padding: 0px 2px 0px 2px;
- margin: 0px 2px 0px 2px;
-}
-
-img.logo {
- float: right;
- border-width: 0px;
-}
-
-div.page_header {
- height: 25px;
- padding: 8px;
- font-size: 150%;
- font-weight: bold;
- background-color: #d9d8d1;
-}
-
-div.page_header a:visited, a.header {
- color: #0000cc;
-}
-
-div.page_header a:hover {
- color: #880000;
-}
-
-div.page_nav {
- padding: 8px;
-}
-
-div.page_nav a:visited {
- color: #0000cc;
-}
-
-div.page_path {
- padding: 8px;
- font-weight: bold;
- border: solid #d9d8d1;
- border-width: 0px 0px 1px;
-}
-
-div.page_footer {
- height: 17px;
- padding: 4px 8px;
- background-color: #d9d8d1;
-}
-
-div.page_footer_text {
- float: left;
- color: #555555;
- font-style: italic;
-}
-
-div.page_body {
- padding: 8px;
- font-family: monospace;
-}
-
-div.title, a.title {
- display: block;
- padding: 6px 8px;
- font-weight: bold;
- background-color: #edece6;
- text-decoration: none;
- color: #000000;
-}
-
-div.readme {
- padding: 8px;
-}
-
-a.title:hover {
- background-color: #d9d8d1;
-}
-
-div.title_text {
- padding: 6px 0px;
- border: solid #d9d8d1;
- border-width: 0px 0px 1px;
- font-family: monospace;
-}
-
-div.log_body {
- padding: 8px 8px 8px 150px;
-}
-
-span.age {
- position: relative;
- float: left;
- width: 142px;
- font-style: italic;
-}
-
-span.signoff {
- color: #888888;
-}
-
-div.log_link {
- padding: 0px 8px;
- font-size: 70%;
- font-family: sans-serif;
- font-style: normal;
- position: relative;
- float: left;
- width: 136px;
-}
-
-div.list_head {
- padding: 6px 8px 4px;
- border: solid #d9d8d1;
- border-width: 1px 0px 0px;
- font-style: italic;
-}
-
-div.author_date {
- padding: 8px;
- border: solid #d9d8d1;
- border-width: 0px 0px 1px 0px;
- font-style: italic;
-}
-
-a.list {
- text-decoration: none;
- color: #000000;
-}
-
-a.subject, a.name {
- font-weight: bold;
-}
-
-table.tags a.subject {
- font-weight: normal;
-}
-
-a.list:hover {
- text-decoration: underline;
- color: #880000;
-}
-
-a.text {
- text-decoration: none;
- color: #0000cc;
-}
-
-a.text:visited {
- text-decoration: none;
- color: #880000;
-}
-
-a.text:hover {
- text-decoration: underline;
- color: #880000;
-}
-
-table {
- padding: 8px 4px;
- border-spacing: 0;
-}
-
-table.diff_tree {
- font-family: monospace;
-}
-
-table.combined.diff_tree th {
- text-align: center;
-}
-
-table.combined.diff_tree td {
- padding-right: 24px;
-}
-
-table.combined.diff_tree th.link,
-table.combined.diff_tree td.link {
- padding: 0px 2px;
-}
-
-table.combined.diff_tree td.nochange a {
- color: #6666ff;
-}
-
-table.combined.diff_tree td.nochange a:hover,
-table.combined.diff_tree td.nochange a:visited {
- color: #d06666;
-}
-
-table.blame {
- border-collapse: collapse;
-}
-
-table.blame td {
- padding: 0px 5px;
- font-size: 100%;
- vertical-align: top;
-}
-
-th {
- padding: 2px 5px;
- font-size: 100%;
- text-align: left;
-}
-
-tr.light:hover {
- background-color: #edece6;
-}
-
-tr.dark {
- background-color: #f6f6f0;
-}
-
-tr.dark2 {
- background-color: #f6f6f0;
-}
-
-tr.dark:hover {
- background-color: #edece6;
-}
-
-td {
- padding: 2px 5px;
- font-size: 100%;
- vertical-align: top;
-}
-
-td.link, td.selflink {
- padding: 2px 5px;
- font-family: sans-serif;
- font-size: 70%;
-}
-
-td.selflink {
- padding-right: 0px;
-}
-
-td.sha1 {
- font-family: monospace;
-}
-
-td.error {
- color: red;
- background-color: yellow;
-}
-
-td.current_head {
- text-decoration: underline;
-}
-
-table.diff_tree span.file_status.new {
- color: #008000;
-}
-
-table.diff_tree span.file_status.deleted {
- color: #c00000;
-}
-
-table.diff_tree span.file_status.moved,
-table.diff_tree span.file_status.mode_chnge {
- color: #777777;
-}
-
-table.diff_tree span.file_status.copied {
- color: #70a070;
-}
-
-/* noage: "No commits" */
-table.repository_list td.noage {
- color: #808080;
- font-style: italic;
-}
-
-/* age2: 60*60*24*2 <= age */
-table.repository_list td.age2, table.blame td.age2 {
- font-style: italic;
-}
-
-/* age1: 60*60*2 <= age < 60*60*24*2 */
-table.repository_list td.age1 {
- color: #009900;
- font-style: italic;
-}
-
-table.blame td.age1 {
- color: #009900;
- background: transparent;
-}
-
-/* age0: age < 60*60*2 */
-table.repository_list td.age0 {
- color: #009900;
- font-style: italic;
- font-weight: bold;
-}
-
-table.blame td.age0 {
- color: #009900;
- background: transparent;
- font-weight: bold;
-}
-
-td.pre, div.pre, div.diff {
- font-family: monospace;
- font-size: 12px;
- white-space: pre;
-}
-
-td.mode {
- font-family: monospace;
-}
-
-/* styling of diffs (patchsets): commitdiff and blobdiff views */
-div.diff.header,
-div.diff.extended_header {
- white-space: normal;
-}
-
-div.diff.header {
- font-weight: bold;
-
- background-color: #edece6;
-
- margin-top: 4px;
- padding: 4px 0px 2px 0px;
- border: solid #d9d8d1;
- border-width: 1px 0px 1px 0px;
-}
-
-div.diff.header a.path {
- text-decoration: underline;
-}
-
-div.diff.extended_header,
-div.diff.extended_header a.path,
-div.diff.extended_header a.hash {
- color: #777777;
-}
-
-div.diff.extended_header .info {
- color: #b0b0b0;
-}
-
-div.diff.extended_header {
- background-color: #f6f5ee;
- padding: 2px 0px 2px 0px;
-}
-
-div.diff a.list,
-div.diff a.path,
-div.diff a.hash {
- text-decoration: none;
-}
-
-div.diff a.list:hover,
-div.diff a.path:hover,
-div.diff a.hash:hover {
- text-decoration: underline;
-}
-
-div.diff.to_file a.path,
-div.diff.to_file {
- color: #007000;
-}
-
-div.diff.add {
- color: #008800;
-}
-
-div.diff.from_file a.path,
-div.diff.from_file {
- color: #aa0000;
-}
-
-div.diff.rem {
- color: #cc0000;
-}
-
-div.diff.chunk_header a,
-div.diff.chunk_header {
- color: #990099;
-}
-
-div.diff.chunk_header {
- border: dotted #ffe0ff;
- border-width: 1px 0px 0px 0px;
- margin-top: 2px;
-}
-
-div.diff.chunk_header span.chunk_info {
- background-color: #ffeeff;
-}
-
-div.diff.chunk_header span.section {
- color: #aa22aa;
-}
-
-div.diff.incomplete {
- color: #cccccc;
-}
-
-div.diff.nodifferences {
- font-weight: bold;
- color: #600000;
-}
-
-div.index_include {
- border: solid #d9d8d1;
- border-width: 0px 0px 1px;
- padding: 12px 8px;
-}
-
-div.search {
- font-size: 100%;
- font-weight: normal;
- margin: 4px 8px;
- float: right;
- top: 56px;
- right: 12px
-}
-
-td.linenr {
- text-align: right;
-}
-
-a.linenr {
- color: #999999;
- text-decoration: none
-}
-
-a.rss_logo {
- float: right;
- padding: 3px 0px;
- width: 35px;
- line-height: 10px;
- border: 1px solid;
- border-color: #fcc7a5 #7d3302 #3e1a01 #ff954e;
- color: #ffffff;
- background-color: #ff6600;
- font-weight: bold;
- font-family: sans-serif;
- font-size: 70%;
- text-align: center;
- text-decoration: none;
-}
-
-a.rss_logo:hover {
- background-color: #ee5500;
-}
-
-span.refs span {
- padding: 0px 4px;
- font-size: 70%;
- font-weight: normal;
- border: 1px solid;
- background-color: #ffaaff;
- border-color: #ffccff #ff00ee #ff00ee #ffccff;
-}
-
-span.refs span.ref {
- background-color: #aaaaff;
- border-color: #ccccff #0033cc #0033cc #ccccff;
-}
-
-span.refs span.tag {
- background-color: #ffffaa;
- border-color: #ffffcc #ffee00 #ffee00 #ffffcc;
-}
-
-span.refs span.head {
- background-color: #aaffaa;
- border-color: #ccffcc #00cc33 #00cc33 #ccffcc;
-}
-
-span.atnight {
- color: #cc0000;
-}
-
-span.match {
- color: #e00000;
-}
-
-div.binary {
- font-style: italic;
-}
+++ /dev/null
-[% gitweb_output %]
+++ /dev/null
-[% INCLUDE 'nav/actions.tt2' object = commit %]
-
-<div class='content'>
- <div>
- [% Repository.name %]
- </div>
-
- [% INCLUDE '_heads.tt2' %]
-</div>
+++ /dev/null
-[% INCLUDE 'nav/actions.tt2' object = commit %]
-
-[%
- INCLUDE '_log_pager.tt2';
- INCLUDE '_history.tt2';
- INCLUDE '_log_pager.tt2';
-%]
--- /dev/null
+[%- sha1 = sha1 || HEAD -%]
+[%-
+ hptr = 0;
+ WHILE hptr < sha1.length - 6;
+ sha1part = sha1.substr(hptr, 6);
+ hptr = hptr + 6;
+ END;
+-%]
+
+<div class='button sha1_holder[% "_invert" IF loop.count && loop.count % 2 %]' style="background-color:#[% sha1part %]"></div>
+[% IF !hide_sha1_output %]
+<div class="sha1_label">[% sha1part %]</div>
+[% END %]
<a
class="rss_logo"
title="[% feed_title %]"
- href="[% c.uri_for('rss', feed_args) %]">RSS</a>
+ href="[% c.uri_for_action('/repository/rss', [Repository.name]) %]">RSS</a>
<a
class="rss_logo"
title="[% feed_title %]"
- href="[% c.uri_for('atom', feed_args) %]">Atom</a>
+ href="[% c.uri_for_action('/repository/atom', [Repository.name]) %]">Atom</a>
[% ELSE %]
<a
class="rss_logo"
- href="[% c.uri_for('opml') %]">OPML</a>
+ href="[% c.uri_for_action('/opml/opml') %]">OPML</a>
<a
class="rss_logo"
- href="[% c.uri_for('repository_index') %]">TXT</a>
+ href="[% c.uri_for('/project_index') %]">TXT</a>
[% END %]
--- /dev/null
+<ul class="pager">
+ [% IF log_lines.first.sha1 != Commit.sha1 || (log_lines.size != 25 && page) %]
+ <li class="pager_prev"><a href='[% c.uri_with(pg => (page||0) + 1) %]'>Newer commits</a></li>
+ [% END %]
+
+ [% IF log_lines.first.sha1 != Commit.sha1 && log_lines.size == 25 %] [% END %]
+
+ [% IF log_lines.size == 25 %]
+ <li class="pager_next"><a href='[% c.uri_with(pg => (page||0) - 1) %]'>Older commits</a></li>
+ [% END %]
+</ul>
-[%- IF language %]<link rel="stylesheet" type="text/css" href="[% c.uri_for('/static/css/syntax/' _ language _ '.css') %]"/>[% END -%]
+[%- FOREACH file = syntax_css %]<link rel="stylesheet" type="text/css" href="[% file %]"/>[% END -%]
-<div class='content'>
- <form method="get" action="/" enctype="application/x-www-form-urlencoded">
- <p class="projsearch">Search:
- <input type="text" name="s" value="[% search_text %]" />
- </p>
- </form>
+[% BLOCK repos_table_headfoot %]
+[% SET cell = type == 'head' ? 'th' : 'td' %]
+<tr>
+ <[% cell %]></[% cell %]>
+ <[% cell %]>Repository</[% cell %]>
+ <!-- XXX These do nothing presently -->
+ <[% cell %]><a class="header" href="/?o=descr">Description</a></[% cell %]>
+ <[% cell %]><a class="header" href="/?o=age">Last change</a></[% cell %]>
+ <[% cell %]><a class="header" href="/?o=owner">By</a></[% cell %]>
+ <[% cell %]>Actions</[% cell %]>
+</tr>
+[% END %]
- <table class="repository_list">
- <thead>
- <tr>
- <th>Repository</th>
- <!-- XXX These do nothing presently -->
- <th><a class="header" href="/?o=descr">Description</a></th>
- <th><a class="header" href="/?o=owner">Owner</a></th>
- <th><a class="header" href="/?o=age">Last Change</a></th>
- <th></th>
- </tr>
- </thead>
- <tfoot>
- <tr>
- <td>Repository</td>
- <!-- XXX These do nothing presently -->
- <td><a href="/?o=descr">Description</a></td>
- <td><a href="/?o=owner">Owner</a></td>
- <td><a href="/?o=age">Last Change</a></td>
- <td></td>
- </tr>
- </tfoot>
+<table class="listing">
+<thead>
+ [% INCLUDE repos_table_headfoot type = 'head' %]
+</thead>
+[% subinclude('/fragment/collectionofrepositories') %]
+</table>
- <tbody class='listing'>
- [% FOR p IN repositories %]
- <tr>
- <td><a class="list" href="[% c.uri_for('/summary', {p=p.name}) %]">[% p.name %]</a></td>
- <td><a class="list" title="[% p.description %]" href="[% c.uri_for('/summary', {p=p.name} ) %]">[% abridged_description(p.description) %]</a></td>
- <td>[% p.owner %]</td>
- <td class="time-since">[% time_since(p.last_change) %]</td>
- <td class="link"><a href="[% c.uri_for("summary", {p=p.name}) %]">summary</a>
- | <a href="[% c.uri_for("shortlog", {p=p.name}) %]">shortlog</a>
- | <a href="[% c.uri_for("log", {p=p.name}) %]">log</a>
- | <a href="[% c.uri_for("tree", {p=p.name}) %]">tree</a></td>
- </tr>
- [% END %]
- </tbody>
- </table>
-</div>
+++ /dev/null
-[% INCLUDE 'nav/actions.tt2' object = commit %]
-
-<div class='content'>
- [% INCLUDE '_log_pager.tt2' %]
-
- <div id='log'>
- [% FOREACH line IN log_lines %]
- <div class='entry'>
- <div class="message">
- [% message = line.comment | html;
- message.replace("\n", "<br/>") %]
- <div class='chroma-hash'>[% INCLUDE '_chroma_hash.tt2' sha1 = line.sha1 %]</div>
- </div>
- <div class="meta">
- <table class='summary' cellspacing='0' cellpadding='0'>
- <tr><td>author</td><td class='author'>[% line.author.name | html %]</td></tr>
- <tr><td>authored time</td><td class='time'>[% line.authored_time %]</td></tr>
- [% IF line.author.name != line.committer.name %]
- <tr><td>committer</td><td class='author'>[% line.committer.name | html %]</td></tr>
- <tr><td>committered time</td><td class='time'>[% line.committed_time %]</td></tr>
- [% END %]
- </table>
- <span class="time-since">[% time_since(line.authored_time) %]</span>
- <div class="action-list">
- <a href="[% c.uri_for("commit", {h=line.sha1}) %]">commit</a>
- | <a href="[% c.uri_for("commitdiff", {h=line.sha1}) %]">commitdiff</a>
- | <a href="[% c.uri_for("tree", {h=line.sha1, hb=line.sha1}) %]">tree</a>
- </div>
- </div>
- </div>
- [% END %]
- </div>
-
- [% INCLUDE '_log_pager.tt2' %]
-</div>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="65"
- height="23"
- id="svg2404"
- sodipodi:version="0.32"
- inkscape:version="0.46"
- version="1.0"
- sodipodi:docname="logo.svg"
- inkscape:output_extension="org.inkscape.output.svg.inkscape"
- inkscape:export-filename="/home/dbrook/dev/gitalist/root/logo.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90">
- <defs
- id="defs2406">
- <inkscape:perspective
- sodipodi:type="inkscape:persp3d"
- inkscape:vp_x="0 : 11.502125 : 1"
- inkscape:vp_y="0 : 1000 : 0"
- inkscape:vp_z="71.847527 : 11.502125 : 1"
- inkscape:persp3d-origin="35.923763 : 7.6680832 : 1"
- id="perspective2400" />
- </defs>
- <sodipodi:namedview
- id="base"
- pagecolor="#ffffff"
- bordercolor="#666666"
- borderopacity="1.0"
- gridtolerance="10000"
- guidetolerance="10"
- objecttolerance="10"
- inkscape:pageopacity="0.0"
- inkscape:pageshadow="2"
- inkscape:zoom="7.9195959"
- inkscape:cx="35.923763"
- inkscape:cy="1.045551"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- showgrid="false"
- inkscape:showpageshadow="false"
- inkscape:window-width="1280"
- inkscape:window-height="950"
- inkscape:window-x="0"
- inkscape:window-y="25">
- <inkscape:grid
- type="xygrid"
- id="grid2449"
- visible="true"
- enabled="true" />
- </sodipodi:namedview>
- <metadata
- id="metadata2409">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Layer 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(-20.793031,-18.938722)">
- <text
- xml:space="preserve"
- style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
- x="60.946594"
- y="35.124443"
- id="text2577"
- sodipodi:linespacing="125%"><tspan
- sodipodi:role="line"
- id="tspan2579"
- x="60.946594"
- y="35.124443"
- style="font-size:20px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Candara;-inkscape-font-specification:Candara Italic">git</tspan></text>
- <path
- style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-opacity:1"
- id="path3357"
- d="M 2.9800098,4.6496528 C 3.2880818,4.6583433 3.5963683,4.6566553 3.9045415,4.6581792 C 4.2900822,4.6480495 4.6799534,4.6882469 5.0628669,4.6352919 C 5.3415627,4.5839381 5.6225883,4.5523136 5.9053688,4.5367547 C 6.1586148,4.525911 6.4121605,4.5264303 6.6655841,4.5263393 C 6.9517438,4.5294138 7.2379286,4.5284888 7.5240995,4.5281299 C 7.7848081,4.527744 8.0455169,4.5275665 8.3062258,4.5274685 C 8.558755,4.527395 8.8112843,4.5273988 9.0638136,4.5273983 C 9.3162235,4.5274 9.5686335,4.5274028 9.8210434,4.5274043 C 10.073574,4.5274055 10.326104,4.5274056 10.578634,4.5274057 C 10.785275,4.5093013 11.024398,4.4841054 11.21515,4.3956888 C 11.416398,4.3090351 11.636109,4.2943885 11.852029,4.2819999 C 11.974627,4.276229 12.097361,4.2751928 12.220063,4.2738955 L 10.717011,5.3706722 C 10.596134,5.3743956 10.475147,5.3777149 10.354734,5.3898714 C 10.143057,5.4148447 9.938646,5.4621628 9.739379,5.5391785 C 9.519194,5.5818357 9.300299,5.6371449 9.0738739,5.6206779 C 8.8213422,5.620678 8.5688106,5.6206781 8.3162789,5.6206801 C 8.0638608,5.6206826 7.8114426,5.6206872 7.5590244,5.6206935 C 7.3065562,5.6206971 7.054088,5.6207114 6.8016198,5.6206066 C 6.5416878,5.6204588 6.2817558,5.6202017 6.0218249,5.6194038 C 5.7348811,5.6185593 5.4479171,5.6167199 5.1609836,5.6200676 C 4.9100951,5.6212274 4.6589774,5.6224823 4.4085648,5.6397412 C 4.1302379,5.6620999 3.8546293,5.7044164 3.5772175,5.7351221 C 3.1892034,5.7518431 2.8004601,5.7331854 2.412181,5.7424426 C 2.0961821,5.7439843 1.7800839,5.7424472 1.464178,5.7509691 L 2.9800098,4.6496528 z"
- transform="translate(20.793031,18.938722)" />
- <path
- style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-opacity:1"
- id="path3359"
- d="M 15.250399,4.5523455 C 15.590061,4.6402633 15.939932,4.6849319 16.280783,4.7668885 C 16.564174,4.8441138 16.854443,4.8817339 17.146909,4.8990287 C 17.399102,4.9098761 17.651613,4.9082786 17.903977,4.9078487 C 18.196362,4.8994477 18.48183,4.9060295 18.769953,4.954769 C 19.026435,5.0019753 19.286577,5.0188065 19.546736,5.0279525 C 19.798361,5.0344119 20.050099,5.0335836 20.301785,5.033395 C 20.554174,5.0330364 20.806562,5.0327599 21.058951,5.0326104 C 21.363806,5.0344648 21.668672,5.0355902 21.973534,5.0351006 C 22.256547,5.0342111 22.53956,5.0333216 22.822574,5.0328558 C 23.076911,5.0325027 23.331247,5.0324842 23.585583,5.0324647 C 23.837759,5.0324579 24.089935,5.0324695 24.34211,5.0324751 C 24.556292,5.0323195 24.775741,4.98369 24.945116,4.8497032 C 22.230527,6.5415415 23.325761,5.7734246 23.936091,5.386159 C 25.664647,4.3818697 25.018714,4.6323031 25.743129,4.3594463 L 24.285165,5.5176185 C 23.679415,5.8500541 24.148817,5.5935527 25.670884,4.7083218 C 24.971451,5.1881669 24.19828,5.5365941 23.494352,6.0234103 C 23.285581,6.1061415 23.061433,6.1343034 22.837331,6.1257613 C 22.585146,6.1257668 22.332961,6.1257785 22.080776,6.1257712 C 21.8268,6.1257511 21.572824,6.1257319 21.318849,6.1253744 C 21.037899,6.1249056 20.75695,6.1240082 20.476001,6.1231311 C 20.168754,6.1226612 19.861503,6.1238295 19.554265,6.1259938 C 19.301825,6.1262062 19.049385,6.1266353 18.796945,6.1266198 C 18.543601,6.1261977 18.290119,6.1261239 18.037005,6.1139367 C 17.773731,6.0982577 17.511863,6.0695772 17.252032,6.0234681 C 16.968885,5.9867088 16.684036,5.9998178 16.399079,6.0011342 C 16.144185,6.0005097 15.888907,6.0003272 15.634679,5.9794826 C 15.340021,5.9501258 15.050044,5.8949689 14.763813,5.8185376 C 14.417768,5.7462516 14.070072,5.6758601 13.720196,5.6259461 L 15.250399,4.5523455 z"
- transform="translate(20.793031,18.938722)" />
- <path
- style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-opacity:1"
- id="path3361"
- d="M 29.263724,4.7095281 C 29.543559,4.8008603 29.827126,4.8860904 30.113393,4.9564493 C 30.34092,5.0605715 30.57723,5.1193953 30.825121,5.1432959 C 31.137783,5.1697008 31.451743,5.1480706 31.763125,5.1862517 C 32.097281,5.2339857 32.433502,5.2624205 32.770587,5.2773118 C 33.034287,5.2866749 33.298197,5.2861541 33.562022,5.2860801 C 33.813967,5.2857484 34.065913,5.2853866 34.317858,5.2851965 C 34.570186,5.2850362 34.822513,5.2850255 35.074841,5.2850147 C 35.352046,5.2851166 35.629234,5.2868659 35.906443,5.2865131 C 36.180245,5.2863591 36.454048,5.2843413 36.727845,5.2864149 C 37.04472,5.2979745 37.355267,5.2922269 37.667843,5.2407986 C 37.96856,5.1837264 38.279499,5.2040028 38.578247,5.1418173 C 38.839416,5.0907446 39.101827,5.0275269 39.35035,4.9310873 C 39.194946,4.9727956 39.826949,4.660365 39.66612,4.7539434 C 36.910653,6.3572034 37.855073,5.8664227 38.350928,5.4796749 L 40.075242,4.7799543 C 39.460002,5.369098 38.652116,5.7191844 37.883509,6.0714455 C 37.623385,6.1466605 37.363086,6.2223438 37.093333,6.255085 C 36.789944,6.2847538 36.484875,6.2995069 36.18379,6.3506077 C 35.865823,6.3867145 35.546458,6.3736197 35.226924,6.376897 C 34.95322,6.3789267 34.67951,6.3769901 34.405801,6.3767916 C 34.127221,6.3764318 33.848662,6.3781783 33.570085,6.3783053 C 33.317768,6.3783415 33.06545,6.3783969 32.813134,6.3786503 C 32.561135,6.3789145 32.309135,6.3794844 32.057136,6.3789155 C 31.792731,6.3776272 31.528163,6.3754747 31.264194,6.358621 C 30.928192,6.3348706 30.59417,6.2935806 30.259243,6.2585132 C 29.9424,6.2411928 29.623899,6.2556697 29.308234,6.216721 C 29.057606,6.1786221 28.823039,6.0968746 28.586692,6.0067869 C 28.293107,5.9246568 27.998707,5.8444301 27.708397,5.7515096 L 29.263724,4.7095281 z"
- transform="translate(20.793031,18.938722)" />
- <path
- style="fill:#00ff00;fill-opacity:1;stroke:none;stroke-opacity:1"
- id="path3363"
- d="M 3.1168348,13.771312 C 3.4871277,13.830242 3.8517342,13.918437 4.2191663,13.993351 C 4.8365888,14.10372 5.4653965,14.120181 6.0908892,14.134004 C 6.6183258,14.131945 7.1429297,14.196644 7.6688677,14.229611 C 8.0515007,14.250739 8.4347714,14.254448 8.8178923,14.254653 C 9.1096113,14.253798 9.4013255,14.251899 9.6930442,14.250937 C 9.9740054,14.249674 10.254968,14.250305 10.535904,14.254183 C 10.982187,14.259328 11.428493,14.259977 11.87479,14.257146 C 12.207864,14.240609 12.545321,14.278998 12.875726,14.230274 C 13.068494,14.196492 13.262384,14.171244 13.457002,14.151266 L 11.967231,15.259246 C 11.774069,15.282733 11.58171,15.312125 11.388239,15.333036 C 11.055505,15.349359 10.72238,15.336526 10.389376,15.336362 C 9.9403422,15.333461 9.4913003,15.334285 9.0422815,15.339402 C 8.7580303,15.343276 8.4737547,15.344192 8.189477,15.343616 C 7.9007121,15.343348 7.611941,15.342724 7.3231966,15.33893 C 6.9406694,15.333468 6.5578076,15.328364 6.1762486,15.298076 C 5.6614564,15.257676 5.1481752,15.190115 4.6309779,15.18897 C 3.9920801,15.170244 3.3496573,15.15468 2.7193715,15.038168 C 2.3411972,14.963105 1.9625517,14.890673 1.5798912,14.842263 L 3.1168348,13.771312 z"
- transform="translate(20.793031,18.938722)" />
- <path
- style="fill:#00ff00;fill-opacity:1;stroke:none;stroke-opacity:1"
- id="path3365"
- d="M 8.6634088,9.7750099 C 8.6458015,10.16178 8.6464925,10.549292 8.6442839,10.93642 C 8.6582983,11.440766 8.6301257,11.942307 8.5881454,12.44451 C 8.5337827,12.858986 8.4688526,13.271539 8.4289363,13.687806 C 8.4021237,14.020874 8.401948,14.355087 8.3983622,14.68895 C 8.3981656,15.018792 8.3983046,15.348617 8.4006285,15.678453 C 8.4028493,15.95185 8.4038991,16.225253 8.4044537,16.498657 C 8.4048478,16.751439 8.40482,17.004221 8.4048186,17.257003 C 8.4298921,17.507752 8.4784656,17.755037 8.5041009,18.005961 C 8.5434103,18.243846 8.5067663,18.474507 8.4645558,18.708057 C 8.4302073,18.897923 8.4195037,19.090656 8.4113731,19.283059 L 6.7503165,20.12233 C 6.7554353,19.923404 6.76162,19.724053 6.7892032,19.526699 C 6.8239609,19.305546 6.8946704,19.092062 6.8549589,18.865832 C 6.8329143,18.608918 6.7901946,18.355593 6.747484,18.101454 C 6.7474896,17.848568 6.7474797,17.595682 6.7478122,17.342797 C 6.7482679,17.068341 6.7491362,16.793887 6.7506446,16.519436 C 6.7520929,16.188741 6.7505754,15.858071 6.7512435,15.527378 C 6.7502863,15.188506 6.7528272,14.849176 6.7774631,14.511059 C 6.8113889,14.090591 6.8881912,13.675821 6.9548568,13.259611 C 6.9964813,12.762612 7.0358084,12.266987 7.0130806,11.767559 C 7.0108963,11.386934 7.0118141,11.005886 6.9939556,10.625639 L 8.6634088,9.7750099 z"
- transform="translate(20.793031,18.938722)" />
- <path
- style="fill:#00ff00;fill-opacity:1;stroke:none;stroke-opacity:1"
- id="path3385"
- d="M 16.418357,13.872083 C 17.620556,13.906529 18.81114,14.095792 20.007704,14.208839 C 21.525842,14.340227 23.049286,14.380783 24.572309,14.397281 L 23.184327,15.399419 C 21.680967,15.324869 20.177069,15.257697 18.675006,15.160028 C 17.424243,15.066311 16.171754,14.895255 14.915705,14.963823 L 16.418357,13.872083 z"
- transform="translate(20.793031,18.938722)" />
- <path
- style="fill:#00ff00;fill-opacity:1;stroke:none;stroke-opacity:1"
- id="path3389"
- d="M 20.665339,9.7587118 C 20.722349,10.222553 20.732976,10.690339 20.742278,11.157055 C 20.752317,11.867666 20.748409,12.578364 20.751788,13.289015 C 20.710129,14.254618 20.729215,15.221865 20.751486,16.187776 C 20.770064,16.589489 20.837044,16.986383 20.87711,17.386039 C 20.897733,17.623421 20.899385,17.86205 20.90283,18.100172 L 19.250272,18.944315 C 19.248893,18.710214 19.246043,18.476078 19.230695,18.242386 C 19.202752,17.829538 19.153408,17.417928 19.150089,17.003664 C 19.172458,16.037771 19.193452,15.070443 19.150914,14.104876 C 19.15304,13.397944 19.150029,12.690864 19.130336,11.984165 C 19.11369,11.535866 19.104462,11.082675 19.013357,10.641937 L 20.665339,9.7587118 z"
- transform="translate(20.793031,18.938722)" />
- <path
- style="fill:#00ff00;fill-opacity:1;stroke:none;stroke-opacity:1"
- id="path3395"
- d="M 27.748495,13.422094 C 28.386624,13.611665 29.070496,13.603923 29.730064,13.632045 C 30.989831,13.655712 32.249313,13.668109 33.508743,13.707449 C 33.974488,13.69315 34.430129,13.792746 34.889985,13.844471 C 35.200366,13.870981 35.509644,13.791535 35.813309,13.73547 C 36.045716,13.691233 36.280557,13.66388 36.515949,13.64216 L 35.029661,14.744938 C 34.799369,14.770068 34.569725,14.800725 34.342514,14.846717 C 34.024589,14.908428 33.699995,14.967203 33.376203,14.914662 C 32.942158,14.850743 32.513228,14.745497 32.071717,14.741097 C 30.826118,14.660344 29.579915,14.646151 28.331923,14.64196 C 27.620099,14.632436 26.882897,14.670449 26.193168,14.464075 L 27.748495,13.422094 z"
- transform="translate(20.793031,18.938722)" />
- <path
- style="fill:#00ff00;fill-opacity:1;stroke:none;stroke-opacity:1"
- id="path3397"
- d="M 32.526448,9.4122312 C 32.500107,9.9556963 32.498962,10.500074 32.495247,11.044059 C 32.492249,11.791325 32.489686,12.538611 32.493317,13.285877 C 32.491367,13.826812 32.50501,14.367614 32.514782,14.908416 C 32.513335,15.237763 32.576715,15.561888 32.603737,15.889377 C 32.627479,16.294591 32.622776,16.699633 32.671404,17.102956 C 32.697134,17.385271 32.74629,17.660115 32.815308,17.934389 C 32.864178,18.127769 32.880543,18.326507 32.892246,18.524917 L 31.23792,19.37883 C 31.229282,19.19133 31.217981,19.003211 31.175925,18.819622 C 31.108969,18.53489 31.057669,18.25152 31.039661,17.958523 C 30.993406,17.553538 30.991036,17.14824 30.966344,16.741621 C 30.935983,16.409373 30.868687,16.079151 30.872291,15.745307 C 30.882015,15.197212 30.895594,14.649118 30.893755,14.100895 C 30.897365,13.354284 30.894848,12.607653 30.891825,11.861043 C 30.888157,11.327662 30.887401,10.793844 30.860624,10.261011 L 32.526448,9.4122312 z"
- transform="translate(20.793031,18.938722)" />
- </g>
-</svg>
+[%- SET object = commit || head -%]
<div class='actions'>
+ <div class="clear"></div>
+ <div class='grid_8'>
<!-- This should probably be a real LIst -->
- <a href="[% c.uri_for('summary') %]">summary</a> •
- <a href="[% c.uri_for('shortlog', {h=object.sha1}) %]">shortlog</a> •
- <a href="[% c.uri_for('log', {h=object.sha1}) %]">log</a> •
- <a href="[% c.uri_for('commit', {h=object.sha1}) %]">commit</a> •
- <a href="[% c.uri_for('commitdiff', {h=object.sha1}) %]">commitdiff</a>
- [% IF object.type == 'commit' %] •
- <a href="[% c.uri_for('tree', {h=object.tree_sha1, hb=object.sha1}) %]">tree</a>
+ <a href="[% c.uri_for_action('/repository/summary', [c.req.captures.0]) %]">summary</a> •
+ [% IF c.req.captures.size == 1; SET path = 'repository'; ELSE; SET path = 'ref'; END %]
+ <a href="[% c.uri_for_action('/' _ path _ '/shortlog', c.req.captures) %]">shortlog</a> •
+ <a href="[% c.uri_for_action('/' _ path _ '/longlog', c.req.captures) %]">log</a>
+ [% IF Commit %]
+ §
+ <a href="[% c.uri_for_action('/ref/commit', [c.req.captures.0, Commit.sha1]) %]">commit</a> •
+ <a href="[% c.uri_for_action('/ref/diff_fancy', [c.req.captures.0, Commit.sha1]) %]">commitdiff</a> •
+ <a href="[% c.uri_for_action('/ref/tree', [c.req.captures.0, Commit.sha1]) %]">tree</a>
[% END %]
- [% IF filename %]
+ [% IF filename && c.action != 'ref/tree' %]
§
- <a href="[% c.uri_for('blob', {h=object.sha1,f=filename}) %]">blob</a> •
- <a href="[% c.uri_for('blob_plain', {h=object.sha1,f=filename}) %]">raw</a> •
- <a href="[% c.uri_for('blame', {h=object.sha1,f=filename}) %]">blame</a> •
- <a href="[% c.uri_for('shortlog', {h=object.sha1,f=filename}) %]">history</a> •
- <a href="[% c.uri_for(action, {f=filename}) %]">HEAD</a>
+ <a href="[% c.uri_for_action('/ref/blob', [c.req.captures.0, Commit.sha1], filename) %]">blob</a> •
+ <a href="[% c.uri_for_action('/ref/raw', [c.req.captures.0, Commit.sha1], filename) %]">raw</a> •
+ <a href="[% c.uri_for_action('/ref/blame', [c.req.captures.0, Commit.sha1], filename) %]">blame</a> •
+ <a href="[% c.uri_for_action('/ref/history', [c.req.captures.0, Commit.sha1], filename) %]">history</a> •
+ <a href="[% c.uri_for(c.controller.action_for('commit'), [c.req.captures.0, Repository.head_hash]) %]">HEAD</a>
[% END %]
- <div class='chroma-hash'>[% INCLUDE '_chroma_hash.tt2' sha1 = object.sha1 %]</div>
+ </div>
+ <div class='grid_4'>[% INCLUDE 'inc/chroma_hash.tt2' sha1 = object.sha1 %]</div>
</div>
-<div class='path'>
- <a href="[% c.uri_for("tree", {hb=head.sha1}) %]">[% Repository.name %]</a>
+ <a href="[% c.uri_for_action("/ref/tree", [Repository.name, Commit.sha1]) %]">[% Repository.name %] (tree)</a>
[% FOREACH part IN filename.split('/') %]
[% path = loop.first ? part : path _ '/' _ part %]
- / <a href="[% c.uri_for(loop.last ? 'blob' : 'tree', {hb=head.sha1,f=path}) %]">[% part %]</a>
+ / <a href="[% action_name = loop.last ? '/ref/blob' : '/ref/tree'; c.uri_for_action(action_name, [Repository.name,Commit.sha1], path.to_path ) %]">[% part %]</a>
[% END %]
-</div>
+
+[% IF Repository %]
<div id="page-search">
- <form method="get" action="[% c.uri_for('search') %]" enctype="application/x-www-form-urlencoded">
- <input name="p" type="hidden" value="[% Repository.name %]">
- <input name="a" type="hidden" value="search">
- <input name="h" type="hidden" value="[% commit.sha1 %]">
- <input name="f" type="hidden" value="[% c.req.param('f') %]">
+ <form method="get" action="[% c.uri_for_action('/repository/search', [Repository.name]) %]" enctype="application/x-www-form-urlencoded">
+ Search
+
+ <input type="text" name="text" value="[% c.req.param('s') %]" />
<select name="type">
<option value="commit">commit</option>
<option value="author">author</option>
<option value="grep">grep</option>
<option value="pickaxe">pickaxe</option>
-->
- </select><sup><a href="[% c.uri_for('search_help') %]">?</a></sup> search:
- <input type="text" name="text" value="[% c.req.param('s') %]">
+ </select>
<span title="Extended regular expression"><label><input type="checkbox" name="regexp" value="1">re</label></span>
+ <sup><a href="[% c.uri_for_action('/search_help') %]">?</a></sup>
+
+ <input type="submit" class="button_submit" value="" />
</form>
</div>
+[% END %]
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+<opml version="1.1">
+ <body>[% count = 1 %]
+ [% FOR Repository = Repositories %]
+ <outline id="[% count %]"
+ description=""
+ text="[% Repository.name | html_entity %] - [% Repository.description | html_entity %]"
+ title=""
+ type="rss"
+ version="RSS"
+ xmlUrl="[% c.uri_for_action('/repository/rss', [ Repository.name ])%]" />
+ [% SET count = count + 1; END %]
+ </body>
+ <head>
+ <dateCreated>[% now %]</dateCreated>
+ <dateModified>[% now %]</dateModified>
+ <title>[% title | html_entity %]</title>
+ </head>
+</opml>
--- /dev/null
+[%- BLOCK blame_table_headfoot %]
+<tr>
+ <th>Author</th>
+ <th>Date</th>
+ <th width="80" nowrap="nowrap">ID (sha1)</thd>
+ <th></tdh>
+ <th class='data'>Data</th>
+</tr>
+[% END -%]
+
+[%- INCLUDE inc/syntax_highlight_css.tt2 -%]
+
+
+
+
+
+
+
+<div id='blame'>
+<table class="listing">
+ <thead>
+ [% PROCESS blame_table_headfoot %]
+ </thead>
+
+ <tbody>
+ [% subinclude('/fragment/ref/blame', c.req.captures, c.req.arguments.to_path ) %]
+ </tbody>
+</table>
+</div>
+
+<h2>[% INCLUDE 'nav/path.tt2' %]</h2>
+
+
+[% IF object.type == 'commit' %]
+<div class='commit-message'>[% short_cmt(head.comment) %]</div>
+[% END %]
+
--- /dev/null
+<h3>[% INCLUDE 'nav/path.tt2' %]</h3>
+
+ [% IF object.type == 'commit' %]
+ <div class='commit-message'>
+ [% short_cmt(head.comment) %]
+ </div>
+ [% END %]
+
+[% subinclude('/fragment/ref/blob', c.req.captures, c.req.args.to_path) %]
+
+
+
\ No newline at end of file
--- /dev/null
+
+<div class='content'>
+ [% subinclude('/fragment/ref/commit', c.req.captures) %]
+</div>
--- /dev/null
+
+<table class='listing'>
+<thead>
+<tr>
+ <th>ID (sha1)</th>
+ <th>Last change</th>
+ <th>Message</th>
+ <th>By</th>
+</tr>
+</thead>
+<tbody>
+<tr class="invert">
+ <td class='sha1' title='[% Commit.sha1 %]'>[% INCLUDE 'inc/chroma_hash.tt2' sha1 = Commit.sha1.substr(0, 7) %]</td>
+ <td class='time-since' title='[% Commit.authored_time %]'>[% time_since(Commit.authored_time) %]</td>
+ <td>[% short_cmt(Commit.comment) | html %]</td>
+ <td class='author'><img src="[% uri_for_gravatar(Commit.committer.email, 21) %]" />[% Commit.author.name | html %]</td>
+</tr>
+</tbody>
+</table>
+
+
+ [%
+ # What I really want is @{ c.req.args }
+ subinclude('/fragment/' _ c.action, c.req.captures, c.req.args.0 c.req.args.1)
+ %]
--- /dev/null
+[% subinclude('/fragment/' _ c.action, c.req.captures, c.req.args.0 c.req.args.1) %]
+
--- /dev/null
+[%# FIXME - Pager links are broken because I can't figure out how to pass the parameters %]
+[% subinclude('/fragment/ref/history', c.req.captures, c.req.args.to_path) %]
--- /dev/null
+[% PROCESS 'repository/longlog.tt2' %]
--- /dev/null
+[% PROCESS 'repository/shortlog.tt2' %]
--- /dev/null
+[% subinclude('/fragment/ref/tree', c.req.captures, c.req.args.to_path) %]
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<feed xmlns="http://purl.org/atom/ns#">
+ <title>[% title | html_entity %]</title>
+ <modified>[% updated %]</modified>
+ [% FOREACH Commit = Commits %]
+ <entry>
+ <title>[% Commit.title | html_entity %]</title>
+ <id>[% Commit.id %]</id>
+ <link rel="alternate" type="text/html" href="[% Commit.id %]" />
+ <content type="xhtml">
+ <div xmlns="http://www.w3.org/1999/xhtml">[% Commit.content | html_entity %]</div>
+ </content>
+ </entry>
+ [% END %]
+</feed>
--- /dev/null
+[% subinclude('/fragment/repository/heads', c.req.captures) %]
--- /dev/null
+[% subinclude('/fragment/' _ c.action, c.req.captures, c.req.parameters) %]
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<rss version="2.0" xmlns:blogChannel="http://backend.userland.com/blogChannelModule">
+
+<channel>
+<title>[% title | html_entity %]</title>
+<link>[% c.uri_for_action('/repository/summary', [Repository.name]) %]</link>
+<description>[% Repository.description | html_entity %]</description>
+<language>[% lang %]</language>
+<pubDate>[% pubDate %]</pubDate>
+<lastBuildDate>[% lastBuildDate %]</lastBuildDate>
+[% FOREACH Commit = Commits %]
+<item>
+<title>[% Commit.title | html_entity %]</title>
+<description>[% Commit.description | html_entity %]</description>
+<guid isPermaLink="true">[% Commit.permaLink %]</guid>
+</item>
+[% END %]
+</channel>
+</rss>
--- /dev/null
+[% BLOCK shortlog_table_headfoot %]
+[% SET cell = type == 'head' ? 'th' : 'td' %]
+<tr>
+ <[% cell %]>ID (sha1)</[% cell %]>
+ <[% cell %]>Last change</[% cell %]>
+ <[% cell %]>Message</[% cell %]>
+ <[% cell %]>By</[% cell %]>
+ <[% cell %]>Actions</[% cell %]>
+</tr>
+[% END %]
+
+<table class='listing'>
+<thead>[% PROCESS shortlog_table_headfoot type = 'head' %]</thead>
+<tbody>
+[% FOREACH result IN results %]
+ <tr [% "class='invert'" IF loop.count % 2 %]>
+ <td class='sha1' title='[% result.sha1 %]'>[% INCLUDE 'inc/chroma_hash.tt2' sha1 = result.sha1.substr(0, 7) %]</td>
+ <td class='time-since' title='[% result.authored_time %]'>[% time_since(result.authored_time) %]</td>
+ <td>[%
+ # XXX This is fragile at best.
+ html_comment = result.comment | html;
+ html_comment.replace(
+ c.req.param('text'), '<span class="match">' _ c.req.param('text') _ '</span>'
+ );
+ %]</td>
+ <td class='author'><img src="[% uri_for_gravatar(result.author.email, 21) %]" />[% result.author.name | html %]</td>
+ <td class='action-list'>
+ <a href="[% c.uri_for_action("/ref/commit", [Repository.name, result.sha1]) %]" title="Commit details" class="button commit">commit</a>
+ <a href="[% c.uri_for_action("/ref/diff_fancy", [Repository.name, result.sha1]) %]" title="Commit difference" class="button diff">commitdiff</a>
+ <a href="[% c.uri_for_action("/ref/tree", [Repository.name, result.sha1]) %]" title="Tree" class="button tree">tree</a>
+ </td>
+</tr>
+[% END %]
+</tbody>
+</table>
\ No newline at end of file
--- /dev/null
+[% subinclude('/fragment/' _ c.action, c.req.captures, c.req.parameters) %]
+
--- /dev/null
+
+
+ <!-- [% subinclude('/fragment/repository/summary', c.req.captures) %]
+
+ <h2><a href='[% c.uri_for(c.controller.action_for('shortlog'), c.req.captures) %]'>shortlog</a></h2> -->
+ [% subinclude('/fragment/repository/shortlog', c.req.captures) %]
+
+ <h2><a href='[% c.uri_for(c.controller.action_for('heads'), c.req.captures) %]'>Branches</a></h2>
+ [% subinclude('/fragment/repository/heads', c.req.captures) %]
+
+ [% IF Repository.tags.size > 0 %]
+ <h2><a href='[% c.uri_for(c.controller.action_for('tags'), c.req.captures) %]'>Tags</a></h2>
+ [% subinclude('/fragment/repository/tags', c.req.captures) %]
+ [% END %]
+
--- /dev/null
+<div class='content'>
+ <div>
+ [% Repository.name %]
+ </div>
+
+ [% subinclude('/fragment/repository/tags', c.req.captures) %]
+</div>
-[% INCLUDE 'nav/actions.tt2' object = commit %]
-<div class='content'>
- [%# INCLUDE '_log_pager.tt2' %]
-
- [%# XXX Nabbed the HTML below from gitweb's log action. %]
- [% FOREACH result IN results %]
- <div class="header">
- <a class="title" href="[% c.uri_for('commit', {h=result.sha1}) %]">
- <span class="age">[% result.authored_time %]</span>
- [% short_cmt(result.comment) | html %]
- </a>
- </div>
-
- <div class="title_text">
- <div class="log_link">
- <a href="[% c.uri_for("", {h=result.sha1}) %]">commit</a>
- | <a href="[% c.uri_for("", {h=result.sha1}) %]">commitdiff</a>
- | <a href="[% c.uri_for("", {h=result.tree_sha1, hb=line.sha1}) %]">tree</a>
- </div>
- <i>[% result.author.name | html %] [% line.authored_time %]</i>
- </div>
-
- <div class="log_body">
- [%
- # XXX This is fragile at best.
- html_comment = result.comment | html;
- html_comment.replace(
- c.req.param('text'), '<span class="match">' _ c.req.param('text') _ '</span>'
- );
- %]
- </div>
- [% END %]
-
- [%# INCLUDE '_log_pager.tt2' %]
-</div>
+search
-[% PROCESS 'nav/actions.tt2' object = head %]
+<h3>Search help</h3>
+<div class="copy">
<p><strong>Pattern</strong> is by default a normal string that is matched precisely (but without
regard to case, except in the case of pickaxe). However, when you check the <em>re</em> checkbox,
the pattern entered is recognized as the POSIX extended
<a href="http://en.wikipedia.org/wiki/Regular_expression">regular expression</a> (also case
insensitive).</p>
+
<dl>
<dt><b>commit</b></dt>
<dd>The commit messages and authorship information will be scanned for the given pattern.</dd>
takes a lot of strain on the server, so please use it wisely. Note that since you may be
interested even in changes just changing the case as well, this search is case sensitive.</dd>
</dl>
-
+</div>
+++ /dev/null
-[% INCLUDE 'nav/actions.tt2' object = commit %]
-
-<div class='content'>
-[%
- INCLUDE '_log_pager.tt2';
- INCLUDE '_shortlog.tt2';
- INCLUDE '_log_pager.tt2';
-%]
-</div>
+++ /dev/null
-/* -----------------------------------------------------------------------
-
-
- Blueprint CSS Framework 0.9
- http://blueprintcss.org
-
- * Copyright (c) 2007-Present. See LICENSE for more info.
- * See README for instructions on how to use Blueprint.
- * For credits and origins, see AUTHORS.
- * This is a compressed file. See the sources in the 'src' directory.
-
------------------------------------------------------------------------ */
-
-/* ie.css */
-body {text-align:center;}
-.container {text-align:left;}
-* html .column, * html div.span-1, * html div.span-2, * html div.span-3, * html div.span-4, * html div.span-5, * html div.span-6, * html div.span-7, * html div.span-8, * html div.span-9, * html div.span-10, * html div.span-11, * html div.span-12, * html div.span-13, * html div.span-14, * html div.span-15, * html div.span-16, * html div.span-17, * html div.span-18, * html div.span-19, * html div.span-20, * html div.span-21, * html div.span-22, * html div.span-23, * html div.span-24 {display:inline;overflow-x:hidden;}
-* html legend {margin:0px -8px 16px 0;padding:0;}
-sup {vertical-align:text-top;}
-sub {vertical-align:text-bottom;}
-html>body p code {*white-space:normal;}
-hr {margin:-8px auto 11px;}
-img {-ms-interpolation-mode:bicubic;}
-.clearfix, .container {display:inline-block;}
-* html .clearfix, * html .container {height:1%;}
-fieldset {padding-top:0;}
-textarea {overflow:auto;}
-input.text, input.title, textarea {background-color:#fff;border:1px solid #bbb;}
-input.text:focus, input.title:focus {border-color:#666;}
-input.text, input.title, textarea, select {margin:0.5em 0;}
-input.checkbox, input.radio {position:relative;top:.25em;}
-form.inline div, form.inline p {vertical-align:middle;}
-form.inline label {position:relative;top:-0.25em;}
-form.inline input.checkbox, form.inline input.radio, form.inline input.button, form.inline button {margin:0.5em 0;}
-button, input.button {position:relative;top:0.25em;}
\ No newline at end of file
+++ /dev/null
-/* -----------------------------------------------------------------------
-
-
- Blueprint CSS Framework 0.9
- http://blueprintcss.org
-
- * Copyright (c) 2007-Present. See LICENSE for more info.
- * See README for instructions on how to use Blueprint.
- * For credits and origins, see AUTHORS.
- * This is a compressed file. See the sources in the 'src' directory.
-
------------------------------------------------------------------------ */
-
-/* print.css */
-body {line-height:1.5;font-family:"Helvetica Neue", Arial, Helvetica, sans-serif;color:#000;background:none;font-size:10pt;}
-.container {background:none;}
-hr {background:#ccc;color:#ccc;width:100%;height:2px;margin:2em 0;padding:0;border:none;}
-hr.space {background:#fff;color:#fff;visibility:hidden;}
-h1, h2, h3, h4, h5, h6 {font-family:"Helvetica Neue", Arial, "Lucida Grande", sans-serif;}
-code {font:.9em "Courier New", Monaco, Courier, monospace;}
-a img {border:none;}
-p img.top {margin-top:0;}
-blockquote {margin:1.5em;padding:1em;font-style:italic;font-size:.9em;}
-.small {font-size:.9em;}
-.large {font-size:1.1em;}
-.quiet {color:#999;}
-.hide {display:none;}
-a:link, a:visited {background:transparent;font-weight:700;text-decoration:underline;}
-a:link:after, a:visited:after {content:" (" attr(href) ")";font-size:90%;}
\ No newline at end of file
+++ /dev/null
-/* -----------------------------------------------------------------------
-
-
- Blueprint CSS Framework 0.9
- http://blueprintcss.org
-
- * Copyright (c) 2007-Present. See LICENSE for more info.
- * See README for instructions on how to use Blueprint.
- * For credits and origins, see AUTHORS.
- * This is a compressed file. See the sources in the 'src' directory.
-
------------------------------------------------------------------------ */
-
-/* reset.css */
-html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, code, del, dfn, em, img, q, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td {margin:0;padding:0;border:0;font-weight:inherit;font-style:inherit;font-size:100%;font-family:inherit;vertical-align:baseline;}
-body {line-height:1.5;}
-table {border-collapse:separate;border-spacing:0;}
-caption, th, td {text-align:left;}
-table, td, th {vertical-align:middle;}
-blockquote:before, blockquote:after, q:before, q:after {content:"";}
-blockquote, q {quotes:"" "";}
-a img {border:none;}
-
-/* typography.css */
-html {font-size:100.01%;}
-body {font-size:85%;color:#222;background:#fff;font-family:"Helvetica Neue", Arial, Helvetica, sans-serif;}
-h1, h2, h3, h4, h5, h6 {font-weight:normal;color:#111;}
-h1 {font-size:3em;line-height:1;margin-bottom:0.5em;}
-h2 {font-size:2em;margin-bottom:0.75em;}
-h3 {font-size:1.5em;line-height:1;margin-bottom:1em;}
-h4 {font-size:1.2em;line-height:1.25;margin-bottom:1.25em;}
-h5 {font-size:1em;font-weight:bold;margin-bottom:1.5em;}
-h6 {font-size:1em;font-weight:bold;}
-h1 img, h2 img, h3 img, h4 img, h5 img, h6 img {margin:0;}
-p {margin:0 0 1.5em;}
-p img.left {float:left;margin:1.5em 1.5em 1.5em 0;padding:0;}
-p img.right {float:right;margin:1.5em 0 1.5em 1.5em;}
-a:focus, a:hover {color:#000;}
-a {color:#009;text-decoration:underline;}
-blockquote {margin:1.5em;color:#666;font-style:italic;}
-strong {font-weight:bold;}
-em, dfn {font-style:italic;}
-dfn {font-weight:bold;}
-sup, sub {line-height:0;}
-abbr, acronym {border-bottom:1px dotted #666;}
-address {margin:0 0 1.5em;font-style:italic;}
-del {color:#666;}
-pre {margin:1.5em 0;white-space:pre;}
-pre, code, tt {font:1.1em 'andale mono', 'lucida console', monospace;line-height:1.5;}
-li ul, li ol {margin:0;}
-ul, ol {margin:0 1.5em 1.5em 0;padding-left:3.333em;}
-ul {list-style-type:disc;}
-ol {list-style-type:decimal;}
-dl {margin:0 0 1.5em 0;}
-dl dt {font-weight:bold;}
-dd {margin-left:1.5em;}
-table {width:100%;}
-th {font-weight:bold;}
-
-caption {background:#eee;}
-.small {font-size:.8em;margin-bottom:1.875em;line-height:1.875em;}
-.large {font-size:1.2em;line-height:2.5em;margin-bottom:1.25em;}
-.hide {display:none;}
-.quiet {color:#666;}
-.loud {color:#000;}
-.highlight {background:#ff0;}
-.added {background:#060;color:#fff;}
-.removed {background:#900;color:#fff;}
-.first {margin-left:0;padding-left:0;}
-.last {margin-right:0;padding-right:0;}
-.top {margin-top:0;padding-top:0;}
-.bottom {margin-bottom:0;padding-bottom:0;}
-
-/* forms.css */
-label {font-weight:bold;}
-fieldset {padding:1.4em;margin:0 0 1.5em 0;border:1px solid #ccc;}
-legend {font-weight:bold;font-size:1.2em;}
-input[type=text], input[type=password], input.text, input.title, textarea, select {background-color:#fff;border:1px solid #bbb;}
-input[type=text]:focus, input[type=password]:focus, input.text:focus, input.title:focus, textarea:focus, select:focus {border-color:#666;}
-input[type=text], input[type=password], input.text, input.title, textarea, select {margin:0.5em 0;}
-input.text, input.title {width:300px;padding:5px;}
-input.title {font-size:1.5em;}
-textarea {width:390px;height:250px;padding:5px;}
-input[type=checkbox], input[type=radio], input.checkbox, input.radio {position:relative;top:.25em;}
-form.inline {line-height:3;}
-form.inline p {margin-bottom:0;}
-.error, .notice, .success {padding:.8em;margin-bottom:1em;border:2px solid #ddd;}
-.error {background:#FBE3E4;color:#8a1f11;border-color:#FBC2C4;}
-.notice {background:#FFF6BF;color:#514721;border-color:#FFD324;}
-.success {background:#E6EFC2;color:#264409;border-color:#C6D880;}
-.error a {color:#8a1f11;}
-.notice a {color:#514721;}
-.success a {color:#264409;}
-
-/* grid.css */
-.container {width:950px;margin:0 auto;}
-.showgrid {background:url(src/grid.png);}
-.column, div.span-1, div.span-2, div.span-3, div.span-4, div.span-5, div.span-6, div.span-7, div.span-8, div.span-9, div.span-10, div.span-11, div.span-12, div.span-13, div.span-14, div.span-15, div.span-16, div.span-17, div.span-18, div.span-19, div.span-20, div.span-21, div.span-22, div.span-23, div.span-24 {float:left;margin-right:10px;}
-.last, div.last {margin-right:0;}
-.span-1 {width:30px;}
-.span-2 {width:70px;}
-.span-3 {width:110px;}
-.span-4 {width:150px;}
-.span-5 {width:190px;}
-.span-6 {width:230px;}
-.span-7 {width:270px;}
-.span-8 {width:310px;}
-.span-9 {width:350px;}
-.span-10 {width:390px;}
-.span-11 {width:430px;}
-.span-12 {width:470px;}
-.span-13 {width:510px;}
-.span-14 {width:550px;}
-.span-15 {width:590px;}
-.span-16 {width:630px;}
-.span-17 {width:670px;}
-.span-18 {width:710px;}
-.span-19 {width:750px;}
-.span-20 {width:790px;}
-.span-21 {width:830px;}
-.span-22 {width:870px;}
-.span-23 {width:910px;}
-.span-24, div.span-24 {width:950px;margin-right:0;}
-input.span-1, textarea.span-1, input.span-2, textarea.span-2, input.span-3, textarea.span-3, input.span-4, textarea.span-4, input.span-5, textarea.span-5, input.span-6, textarea.span-6, input.span-7, textarea.span-7, input.span-8, textarea.span-8, input.span-9, textarea.span-9, input.span-10, textarea.span-10, input.span-11, textarea.span-11, input.span-12, textarea.span-12, input.span-13, textarea.span-13, input.span-14, textarea.span-14, input.span-15, textarea.span-15, input.span-16, textarea.span-16, input.span-17, textarea.span-17, input.span-18, textarea.span-18, input.span-19, textarea.span-19, input.span-20, textarea.span-20, input.span-21, textarea.span-21, input.span-22, textarea.span-22, input.span-23, textarea.span-23, input.span-24, textarea.span-24 {border-left-width:1px!important;border-right-width:1px!important;padding-left:5px!important;padding-right:5px!important;}
-input.span-1, textarea.span-1 {width:18px!important;}
-input.span-2, textarea.span-2 {width:58px!important;}
-input.span-3, textarea.span-3 {width:98px!important;}
-input.span-4, textarea.span-4 {width:138px!important;}
-input.span-5, textarea.span-5 {width:178px!important;}
-input.span-6, textarea.span-6 {width:218px!important;}
-input.span-7, textarea.span-7 {width:258px!important;}
-input.span-8, textarea.span-8 {width:298px!important;}
-input.span-9, textarea.span-9 {width:338px!important;}
-input.span-10, textarea.span-10 {width:378px!important;}
-input.span-11, textarea.span-11 {width:418px!important;}
-input.span-12, textarea.span-12 {width:458px!important;}
-input.span-13, textarea.span-13 {width:498px!important;}
-input.span-14, textarea.span-14 {width:538px!important;}
-input.span-15, textarea.span-15 {width:578px!important;}
-input.span-16, textarea.span-16 {width:618px!important;}
-input.span-17, textarea.span-17 {width:658px!important;}
-input.span-18, textarea.span-18 {width:698px!important;}
-input.span-19, textarea.span-19 {width:738px!important;}
-input.span-20, textarea.span-20 {width:778px!important;}
-input.span-21, textarea.span-21 {width:818px!important;}
-input.span-22, textarea.span-22 {width:858px!important;}
-input.span-23, textarea.span-23 {width:898px!important;}
-input.span-24, textarea.span-24 {width:938px!important;}
-.append-1 {padding-right:40px;}
-.append-2 {padding-right:80px;}
-.append-3 {padding-right:120px;}
-.append-4 {padding-right:160px;}
-.append-5 {padding-right:200px;}
-.append-6 {padding-right:240px;}
-.append-7 {padding-right:280px;}
-.append-8 {padding-right:320px;}
-.append-9 {padding-right:360px;}
-.append-10 {padding-right:400px;}
-.append-11 {padding-right:440px;}
-.append-12 {padding-right:480px;}
-.append-13 {padding-right:520px;}
-.append-14 {padding-right:560px;}
-.append-15 {padding-right:600px;}
-.append-16 {padding-right:640px;}
-.append-17 {padding-right:680px;}
-.append-18 {padding-right:720px;}
-.append-19 {padding-right:760px;}
-.append-20 {padding-right:800px;}
-.append-21 {padding-right:840px;}
-.append-22 {padding-right:880px;}
-.append-23 {padding-right:920px;}
-.prepend-1 {padding-left:40px;}
-.prepend-2 {padding-left:80px;}
-.prepend-3 {padding-left:120px;}
-.prepend-4 {padding-left:160px;}
-.prepend-5 {padding-left:200px;}
-.prepend-6 {padding-left:240px;}
-.prepend-7 {padding-left:280px;}
-.prepend-8 {padding-left:320px;}
-.prepend-9 {padding-left:360px;}
-.prepend-10 {padding-left:400px;}
-.prepend-11 {padding-left:440px;}
-.prepend-12 {padding-left:480px;}
-.prepend-13 {padding-left:520px;}
-.prepend-14 {padding-left:560px;}
-.prepend-15 {padding-left:600px;}
-.prepend-16 {padding-left:640px;}
-.prepend-17 {padding-left:680px;}
-.prepend-18 {padding-left:720px;}
-.prepend-19 {padding-left:760px;}
-.prepend-20 {padding-left:800px;}
-.prepend-21 {padding-left:840px;}
-.prepend-22 {padding-left:880px;}
-.prepend-23 {padding-left:920px;}
-div.border {padding-right:4px;margin-right:5px;border-right:1px solid #eee;}
-div.colborder {padding-right:24px;margin-right:25px;border-right:1px solid #eee;}
-.pull-1 {margin-left:-40px;}
-.pull-2 {margin-left:-80px;}
-.pull-3 {margin-left:-120px;}
-.pull-4 {margin-left:-160px;}
-.pull-5 {margin-left:-200px;}
-.pull-6 {margin-left:-240px;}
-.pull-7 {margin-left:-280px;}
-.pull-8 {margin-left:-320px;}
-.pull-9 {margin-left:-360px;}
-.pull-10 {margin-left:-400px;}
-.pull-11 {margin-left:-440px;}
-.pull-12 {margin-left:-480px;}
-.pull-13 {margin-left:-520px;}
-.pull-14 {margin-left:-560px;}
-.pull-15 {margin-left:-600px;}
-.pull-16 {margin-left:-640px;}
-.pull-17 {margin-left:-680px;}
-.pull-18 {margin-left:-720px;}
-.pull-19 {margin-left:-760px;}
-.pull-20 {margin-left:-800px;}
-.pull-21 {margin-left:-840px;}
-.pull-22 {margin-left:-880px;}
-.pull-23 {margin-left:-920px;}
-.pull-24 {margin-left:-960px;}
-.pull-1, .pull-2, .pull-3, .pull-4, .pull-5, .pull-6, .pull-7, .pull-8, .pull-9, .pull-10, .pull-11, .pull-12, .pull-13, .pull-14, .pull-15, .pull-16, .pull-17, .pull-18, .pull-19, .pull-20, .pull-21, .pull-22, .pull-23, .pull-24 {float:left;position:relative;}
-.push-1 {margin:0 -40px 1.5em 40px;}
-.push-2 {margin:0 -80px 1.5em 80px;}
-.push-3 {margin:0 -120px 1.5em 120px;}
-.push-4 {margin:0 -160px 1.5em 160px;}
-.push-5 {margin:0 -200px 1.5em 200px;}
-.push-6 {margin:0 -240px 1.5em 240px;}
-.push-7 {margin:0 -280px 1.5em 280px;}
-.push-8 {margin:0 -320px 1.5em 320px;}
-.push-9 {margin:0 -360px 1.5em 360px;}
-.push-10 {margin:0 -400px 1.5em 400px;}
-.push-11 {margin:0 -440px 1.5em 440px;}
-.push-12 {margin:0 -480px 1.5em 480px;}
-.push-13 {margin:0 -520px 1.5em 520px;}
-.push-14 {margin:0 -560px 1.5em 560px;}
-.push-15 {margin:0 -600px 1.5em 600px;}
-.push-16 {margin:0 -640px 1.5em 640px;}
-.push-17 {margin:0 -680px 1.5em 680px;}
-.push-18 {margin:0 -720px 1.5em 720px;}
-.push-19 {margin:0 -760px 1.5em 760px;}
-.push-20 {margin:0 -800px 1.5em 800px;}
-.push-21 {margin:0 -840px 1.5em 840px;}
-.push-22 {margin:0 -880px 1.5em 880px;}
-.push-23 {margin:0 -920px 1.5em 920px;}
-.push-24 {margin:0 -960px 1.5em 960px;}
-.push-1, .push-2, .push-3, .push-4, .push-5, .push-6, .push-7, .push-8, .push-9, .push-10, .push-11, .push-12, .push-13, .push-14, .push-15, .push-16, .push-17, .push-18, .push-19, .push-20, .push-21, .push-22, .push-23, .push-24 {float:right;position:relative;}
-.prepend-top {margin-top:1.5em;}
-.append-bottom {margin-bottom:1.5em;}
-.box {padding:1.5em;margin-bottom:1.5em;background:#E5ECF9;}
-hr {background:#ddd;color:#ddd;clear:both;float:none;width:100%;height:.1em;margin:0 0 1.45em;border:none;}
-hr.space {background:#fff;color:#fff;visibility:hidden;}
-.clearfix:after, .container:after {content:"\0020";display:block;height:0;clear:both;visibility:hidden;overflow:hidden;}
-.clearfix, .container {display:block;}
-.clear {clear:both;}
--- /dev/null
+#debug_holder{
+
+ display:none;
+
+ clear:both;
+ padding-top:30px;
+ margin:30px 0;
+}
+
+#debug_holder pre{
+ margin:0;
+ padding:10px;
+ border:1px solid #ddd;
+ background-color:#f0f0f0;
+}
+
+body{
+ background:#FAFAFA url([% c.uri_for('/static/i/bg.png') %]) repeat-x left top;
+ padding:0;
+ margin:0;
+ font-family:Arial, Verdana, sans-serif;
+ font-size:80%;
+}
+a img{
+ border:0;
+}
+
+
+/* structure */
+.sub_holder{
+ width:970px;
+ margin:0 auto;
+ text-align:left;
+}
+
+#header_holder{
+ margin-top:20px;
+}
+#header{
+ height:60px;
+}
+
+#content_holder{
+ background:transparent url([% c.uri_for('/static/i/bg_content.png') %]) repeat-y center center;
+}
+#content{
+ min-height:200px;
+ padding:0 12px 40px 10px;
+ background:transparent url([% c.uri_for('/static/i/bg_bottom.png') %]) no-repeat center bottom;
+}
+#content_inner{
+ padding-bottom:30px;
+ background:transparent url([% c.uri_for('/static/i/bg_top.png') %]) no-repeat;
+}
+.copy{
+ padding:10px;
+}
+#logo{
+ margin-left:-10px;
+ float:left;
+}
+#header .search{
+ margin-right:10px;
+ float:right;
+}
+#git_logo{
+ float:left;
+ margin-left:15px;
+}
+#feeds{
+ float:right;
+ margin-right:15px;
+}
+#footer_holder{
+ margin-bottom:100px;
+}
+#footer p{
+ margin-left:15px;
+}
+
+
+/* nav tabs */
+#nav_logs{
+ width:100%;
+ clear:both;
+ float:right;
+ margin:-5px 10px 0 0;
+}
+#nav_logs ul{
+ margin:0;
+ padding:0;
+}
+#nav_logs li{
+ display:block;
+ float:right;
+ list-style:none;
+ margin:0;
+ padding:0;
+}
+#nav_logs li a{
+ display:block;
+ margin-left:20px;
+ padding:10px 15px 10px 48px;
+ color:#ffffff;
+ font-size:1.4em;
+ text-transform:uppercase;
+ text-decoration:none;
+}
+a#log_short{
+ background:#666 url([% c.uri_for('/static/i/icons/shortlog.gif') %]) no-repeat 15px center;
+}
+a#log_full{
+ background:#666 url([% c.uri_for('/static/i/icons/fulllog.gif') %]) no-repeat 15px center;
+}
+a#tree{
+ background:#666 url([% c.uri_for('/static/i/icons/tree.gif') %]) no-repeat 15px center;
+}
+#nav_logs li a:hover{
+ text-decoration:underline;
+ background-color:#DC143C;
+}
+#nav_logs li.selected a{
+ background-color:#333;
+}
+#nav_logs #branch_selector{
+ padding:10px 15px 10px 48px;
+ font-size:1.3em;
+ font-weight:bold;
+ color:#666;
+}
+
+
+
+
+
+/* formating */
+h1{
+ margin:0;
+ padding:20px 0;
+ clear:both;
+ font-weight:normal;
+ font-size:1.85em;
+ color:#fff;
+}
+h1 a{
+ margin-right:10px;
+ color:#fff;
+}
+h1 a:hover{
+ color:#EAF2F5;
+}
+h2{
+ font-size:1.85em;
+ font-weight:normal;
+ color:#666;
+ margin:30px 15px 20px;
+}
+h2 span{
+ color:#ccc;
+}
+h3{
+ margin:0;
+ color:#fff;
+ padding:9px 5px 9px 10px;
+ font-size:1em;
+}
+h3 a{
+ color:#ffffff;
+}
+h4 a{
+ color:#ffffff;
+}
+h4 a:hover{
+ color:#EAF2F5;
+}
+p,
+td,
+a{
+ color:#666;
+}
+a:hover{
+ color:#DC143C;
+}
+
+/* sub actions dropdown changer in h1 */
+#actions_nav_link{
+ border:1px solid #666;
+ padding:1px 4px;
+ text-decoration:none;
+ outline:none;
+}
+#actions_nav_link span{
+ margin-right:5px;
+ padding-right:18px;
+
+ background:transparent url([% c.uri_for('/static/i/arrow_down_white.gif') %]) no-repeat right center;
+}
+#actions_nav_list{
+ display:none;
+ position:absolute;
+ padding:0 0 3px 0;
+ margin:0;
+ background-color:#333;
+ color:#fff;
+ font-size:1em;
+ border:1px solid #666;
+ border-top:none;
+}
+#actions_nav_list li{
+ list-style:none;
+ margin:0;
+ padding:2px 10px 2px 5px;
+}
+#actions_nav_list a{
+ color:#fff;
+ font-size:1.8em;
+}
+#actions_nav_list a:hover{
+ color:#EAF2F5;
+}
+.actions_nav_list_over{
+ display:block !important;
+}
+.button{
+ display:block;
+ float:left;
+ vertical-align:middle;
+ margin-right:8px;
+ text-indent:-999999px;
+ width:21px;
+ height:21px;
+ outline:none;
+}
+a.commit{
+ background:transparent url([% c.uri_for('/static/i/icons/commit.png') %]) no-repeat;
+}
+a.diff{
+ background:transparent url([% c.uri_for('/static/i/icons/diff.png') %]) no-repeat;
+}
+a.diffcurrent{
+ background:transparent url([% c.uri_for('/static/i/icons/diffcurrent.png') %]) no-repeat;
+}
+a.tree{
+ background:transparent url([% c.uri_for('/static/i/icons/tree.png') %]) no-repeat;
+}
+a.shortlog{
+ background:transparent url([% c.uri_for('/static/i/icons/shortlog.png') %]) no-repeat;
+}
+a.longlog{
+ background:transparent url([% c.uri_for('/static/i/icons/longlog.png') %]) no-repeat;
+}
+a.blob{
+ background:transparent url([% c.uri_for('/static/i/icons/blob.png') %]) no-repeat;
+}
+a.blame{
+ background:transparent url([% c.uri_for('/static/i/icons/blame.png') %]) no-repeat;
+}
+a.history{
+ background:transparent url([% c.uri_for('/static/i/icons/history.png') %]) no-repeat;
+}
+a.raw{
+ background:transparent url([% c.uri_for('/static/i/icons/raw.png') %]) no-repeat;
+}
+.sha1_holder{
+ background:transparent url([% c.uri_for('/static/i/icons/button_sha1.png') %]) no-repeat;
+}
+.sha1_holder_invert{
+ background:transparent url([% c.uri_for('/static/i/icons/button_sha1_invert.png') %]) no-repeat;
+}
+.sha1_label{
+ padding-top:2px;
+ float:left;
+}
+a.file{
+ padding-left:25px;
+ background:transparent url([% c.uri_for('/static/i/icons/file.png') %]) no-repeat;
+}
+a.folder{
+ padding-left:25px;
+ background:transparent url([% c.uri_for('/static/i/icons/folder.png') %]) no-repeat;
+}
+.msg{
+ padding:5px 10px 5px 35px;
+ background:#f0f0f0 url([% c.uri_for('/static/i/icons/attention.png') %]) no-repeat 10px center;
+ border:1px solid #ddd;
+ margin:30px 15px;
+}
+.match{
+ background-color:#ffff00;
+}
+a.rss_logo {
+ float: right;
+ padding: 3px 0px;
+ width: 35px;
+ line-height: 10px;
+ border: 1px solid;
+ border-color: #fcc7a5 #7d3302 #3e1a01 #ff954e;
+ color: #ffffff;
+ background-color: #ff6600;
+ font-weight: bold;
+ font-family: sans-serif;
+ font-size: 70%;
+ font-style: normal;
+ text-align: center;
+ text-decoration: none;
+ margin: 3px;
+}
+
+a.rss_logo:hover {
+ background-color: #ee5500;
+}
+
+
+.button_submit{
+ text-indent:-999999px;
+ overflow:hidden;
+ width:95px;
+ height:26px;
+ border:0;
+ background:transparent url([% c.uri_for('/static/i/buttons/search.png') %]) no-repeat;
+ cursor: pointer;
+}
+
+
+/* paging */
+.pager{
+ width:100%;
+ float:left;
+ margin:10px 0;
+ padding:0;
+}
+.pager li{
+ margin:0;
+ padding:0;
+ display:block;
+ list-style:none;
+}
+.pager li a{
+ display:block;
+ padding:4px 6px;
+ color:#fff;
+ border:1px solid #ddd;
+ background-color:#333;
+}
+.pager .pager_prev a{
+ margin-left:20px;
+ float:left;
+}
+.pager .pager_next a{
+ margin-right:20px;
+ float:right;
+}
+
+
+
+
+/* table listings */
+th{
+ padding:9px 5px 9px 10px;
+ text-align:left;
+ color:#fff;
+}
+th a{
+ color:#fff;
+}
+th a:hover{
+ color:#f0f0f0;
+}
+.summary tr{
+ background-color:#FAFAFA;
+ border-bottom:1px solid #fff;
+}
+.summary td{
+ vertical-align:middle !important;
+}
+tr{
+ background-color:#fff;
+}
+thead tr{
+ background-color:transparent !important;
+}
+tr.invert{
+ background-color:#f0f0f0;
+}
+tr.header{
+ background-color:#666;
+}
+.sha1{
+ width:80px;
+}
+.file-mode{
+ width:80px;
+}
+.time-since{
+ width:95px;
+ font-weight:bold;
+}
+.author{
+ width:180px;
+}
+.author img{
+ margin-right:5px;
+ vertical-align:middle;
+}
+table.listing{
+ width:970px;
+ border-collapse:collapse;
+}
+.listing td{
+ vertical-align:top;
+ padding:9px 5px 9px 10px;
+}
+
+/*
+
+puts the repo description on one line which gets truncated if the repo name is too long
+BUT the final width needs to be set with javascript based on the parent element (td) width
+
+.description{
+ white-space:nowrap;
+ overflow:hidden;
+}
+.description div{
+ position:absolute;
+ white-space:nowrap;
+ overflow:hidden;
+ width:200px;
+}
+*/
+
+.action-list{
+ width:120px;
+}
+
+.diff-tree{
+ background-color:#f0f0f0;
+}
+.diff-tree th{
+ background-color:#666;
+}
+.diff-tree tr{
+ border-bottom:1px solid #fff;
+}
+.diff-tree td{
+ padding:6px 5px 4px 10px;
+}
+.differences{
+ margin-top:0;
+ padding:0px 15px;
+}
+.differences pre{
+ line-height:140%;
+ font-size:12px;
+ overflow:auto;
+ margin:0;
+ padding:10px;
+ border:1px solid #ddd;
+ background-color:#f0f0f0;
+ min-height:40px;
+}
+.diff-head{
+ background-color:#666;
+ color:#fff;
+ margin:10px 0 0 0 !important;
+ border:1px solid #ddd;
+ border-bottom:none;
+ font-family: monospace;
+ padding:10px;
+ font-size:13px;
+}
+.diff-index {
+ margin:0 0 30px 0;
+ border:1px solid #ddd;
+ border-top:none;
+ background-color:#ccc;
+ padding:5px 10px;
+}
+
+
+/* /blame */
+#blame pre, #blame tt {
+ margin: 0;
+ font-size: 12px;
+}
+#blame .commit-info {
+
+}
+#blame .lineno {
+ text-align: right;
+ padding: 0 8px;
+}
+#blame a {
+ atext-decoration: none;
+}
+#blame {
+ overflow-x: scroll;
+}
+#blame tr.alt {
+ background-color: #f7f7f7;
+}
+#blame tbody tr:hover {
+ background-color: #fefeaa;
+}
+#blame td {
+ vertical-align:middle;
+ padding: 3px;
+}
+#blame td.lineno {
+ background-color: #eee;
+}
+#blame td.date, #blame td.author, #blame td.commit-info {
+}
+#blame tbody td.data {
+ padding-left: 5px;
+ background-color: #333;
+ color: #ddd;
+}
+
+/* /blob */
+pre.blob {
+ background-color: #333;
+ color: #ddd;
+ border-left: solid 3px #c33;
+ padding: 5px;
+ padding-left: 15px;
+ margin: 20px 15px 20px;
+ overflow:auto;
+ font-size:12px;
+}
+div.blob {
+ text-align: center;
+ margin: 30px;
+}
+
+/* /blobdiff etc */
+
+/* Hidden spans that contain bits of data to be used by JS */
+.js-data {
+ display: none;
+}
+++ /dev/null
-#the-container {
- margin: 1em 100px;
- text-align: center;
- background-color: white;
-}
-#body {
- text-align: justify;
-}
-div.content {
- padding: 0 7px;
-}
-
-/*
-14d2f2ca3732551d1585e7590e60b82492f3
-^^ A rather nice chroma hash
-*/
-body {
- background-color: #555;
-}
-
-thead, tfoot {
- /* FTR all table columns should be sortable hence the colour to indicate clickableness. */
- color: navy;
- font-size: small;
- font-weight: bold !important;
-}
-thead th {
- border-bottom: solid 1px #777;
-}
-tfoot td {
- border-top: solid 1px #777;
-}
-
-.listing tbody tr:nth-child(even) {
- background-color: #f7f7f7;
-}
-.listing tbody tr:hover {
- background-color: #fefeaa;
-}
-
-.chroma-hash {
- font-family: monospace;
- font-size: 1em;
- font-style: normal;
-}
-div.chroma-hash {
- float: right;
-}
-
-.time-since {
- font-style: italic;
-}
-.author, .head {
- font-weight: bold;
- font-family: "Trebuchet MS", "Lucida Grande", serif;
-}
-
-.file-name, .file-mode {
- font-family: monospace;
-}
-.action-list {
- font-size: smaller;
-}
-
-.path {
- border-bottom: solid 1px #ddd;
- padding: 3px 0;
- font-weight: bold;
-}
-
-
-/* header */
-#page-header {
- height: 25px;
- padding: 8px;
- font-size: 1.5em;
- font-weight: bold;
- border-bottom: solid 1px #777;
- text-align: justify;
-}
-
-img.logo {
- float: right;
- border-width: 0px;
- margin-top: 4px;
-}
-
-/* footer */
-#page-footer {
- height: 20px;
- padding: 8px;
- margin-top: 10px;
- font-style: italic;
- background-color: #d9d8d1;
- border-top: solid 1px #777;
-}
-
-/* actions include */
-.actions {
- padding-bottom: 4px 0;
- font-style: italic;
- border-bottom: solid 1px #777;
- margin-bottom: 10px;
- padding: 5px 7px;
-}
-
-/* pager include */
-.pager {
- text-align: center;
-}
-
-/* search include */
-#page-search {
- text-align: right;
- float: right;
- font-size: 0.7em;
- padding-right: 20px;
-}
-
-/* shortlog include */
-table.shortlog tbody tr {
- padding: 1px 0px;
-}
-table.shortlog tbody td {
- padding: 0 1px;
-}
-
-/* /commit page */
-.commit-message {
- font-family: monospace;
- font-size: 1.2em;
-}
-div.commit-message {
- margin-bottom: 10px;
-}
-pre.commit-message {
- border-top: solid 2px red;
- border-bottom: solid 2px green;
- padding: 5px;
-}
-.commit-info dt {
- font-weight: bold;
-}
-.commit-info dd {
- font-family: monospace;
-}
-
-/* /heads */
-.heads .head {
- font-weight: bold;
-}
-.heads .current {
- text-decoration: underline;
-}
-table.heads {
- width: 75%;
-}
-
-/* /blame */
-#blame pre, #blame tt {
- margin: 0;
- font-size: 0.9em;
-}
-#blame .commit-info {
-}
-#blame .lineno {
- text-align: right;
- padding: 0 8px;
-}
-#blame a {
- text-decoration: none;
-}
-#blame {
- overflow-x: scroll;
-}
-#blame tr.alt {
- background-color: #f7f7f7;
-}
-#blame tbody tr:hover {
- background-color: #fefeaa;
-}
-#blame td {
- padding: 0 0.2em;
-}
-#blame td.lineno {
- background-color: #eee;
-}
-#blame td.date, #blame td.author, #blame td.commit-info {
-}
-#blame .data {
- padding-left: 5px;
-}
-
-/* /blob */
-pre.blob {
- background-color: #333;
- color: #ddd;
- border-left: solid 3px #c33;
- padding: 5px;
- padding-left: 15px;
- margin: 10px 15px;
-}
-
-/* /blobdiff etc */
-
-.diff-head, .diff-index {
- font-family: monospace;
-}
-.diff-head {
- border-top: solid 1px red;
-}
-.diff-index {
- border-bottom: solid 1px green;
-}
-
-/* /commitdiff */
-.diff-patch {
- font-size: 0.8em;
-}
-
-/* /log */
-#log .entry {
- border: solid 1px grey;
- margin: 5px 0;
- padding: 5px;
-}
-#log .meta {
- border-top: dotted 1px #ddd;
- color: #311;
-}
-#log table.summary {
- width: 33%;
- font-size: 0.9em;
-}
-#log .message {
- font-family: monospace;
- font-size: 1.15em;
- /* XXX Need to enforce find the CSS switch to force the chroma-hash below the message box */
-}
-#log .age {
- float: right;
- font-size: 0.85em;
- font-style: italic;
-}
-
-/* /summary */
-#stats {
- float: right;
-}
-
-/* /tree */
-table.tree {
- width: 65%;
-}
-
-/* Formerly of gitweb.css */
-
-span.refs span {
- padding: 0px 4px;
- font-size: 80%;
- /* XXX needs more families */
- font-family: Verdana;
- letter-spacing: -1px;
- border: 1px solid;
- background-color: #ffaaff;
- border-color: #ffccff #ff00ee #ff00ee #ffccff;
-}
-
-span.refs span.ref {
- background-color: #aaaaff;
- border-color: #ccccff #0033cc #0033cc #ccccff;
-}
-
-span.refs span.tag {
- background-color: #ffffaa;
- border-color: #ffffcc #ffee00 #ffee00 #ffffcc;
-}
-
-span.refs span.head {
- background-color: #aaffaa;
- border-color: #ccffcc #00cc33 #00cc33 #ccffcc;
-}
-span.refs a {
- text-decoration: none;
-}
-
-a.rss_logo {
- float: right;
- padding: 3px 0px;
- width: 35px;
- line-height: 10px;
- border: 1px solid;
- border-color: #fcc7a5 #7d3302 #3e1a01 #ff954e;
- color: #ffffff;
- background-color: #ff6600;
- font-weight: bold;
- font-family: sans-serif;
- font-size: 70%;
- font-style: normal;
- text-align: center;
- text-decoration: none;
-}
-
-a.rss_logo:hover {
- background-color: #ee5500;
-}
span.Keyword {
- color: #777;
+ color: #aaa;
font-weight: bold;
}
span.DataType {
+ background-color:#F3E6FF;
color: purple;
}
span.Normal {
- color: gray;
+
}
span.String {
- color: green;
+ background-color:#CCF5CC;
+ padding:2px 0;
+ color: #006F00;
}
span.Others {
- color: red;
+ background-color:#F3CCCC;
+ padding:2px 0;
+ color: #750000;
}
--- /dev/null
+function findPos(obj) {
+ var curleft = curtop = 0;
+ if (obj.offsetParent) {
+ do {
+ curleft += obj.offsetLeft;
+ curtop += obj.offsetTop;
+ }
+ while (obj = obj.offsetParent);
+ return [curleft,curtop];
+ }
+}
+
+function setNavClass(el){
+ var link_el = document.getElementById("actions_nav_link");
+ var offsetAry = findPos(link_el);
+ // set position of list
+ el.style.left = offsetAry[0]+"px";
+ el.style.top = offsetAry[1]+30 +"px";
+ el.className+=" actions_nav_list_over";
+}
+
+// handles hover sub menus in IE
+function startList() {
+ if(!document.getElementById("actions_nav_link"))
+ return;
+ var navList = document.getElementById("actions_nav_list");
+ var navLink = document.getElementById("actions_nav_link");
+ // assign event handlers to each element
+ navLink.onmouseover=function() {
+ setNavClass(navList);
+ };
+ navList.onmouseover=function() {
+ setNavClass(navList);
+ };
+ navList.onmouseout=function() {
+ navList.className=navList.className.replace(" actions_nav_list_over", "");
+ };
+ navLink.onmouseout=function() {
+ navList.className=navList.className.replace(" actions_nav_list_over", "");
+ };
+}
+
+function uriFor(action, sha1) {
+ return jQuery('#' + action + '-uri').text().replace(/\bHEAD\b/, sha1);
+}
+
+function switchBranch() {
+ var branch = jQuery('#branch-list').val();
+ document.location.href = uriFor('current', branch);
+}
+
+function compareDiffs(){
+ var path = jQuery('#compare-path').text(),
+ baseSha1 = jQuery('#compare-form input[name=sha1_a]:checked').val(),
+ compSha1 = jQuery('#compare-form input[name=sha1_b]:checked').val(),
+ diffUri = uriFor('diff', baseSha1);
+ document.location.href = diffUri + '/' + compSha1 + (path ? '/' + encodeURIComponent(path) : '');
+ return false;
+}
+
+function _loadCommitInfo(cells) {
+ var cell = jQuery(cells.shift());
+ var filename = cell.find('.js-data').text();
+ jQuery.getJSON(uriFor('file_commit_info') + '/' + filename, {}, function(commitInfo) {
+ cell.empty();
+ cell.html('<a href="'+uriFor('commit', commitInfo.sha1)+'">'+commitInfo.comment+'</a> '+commitInfo.age);
+ if(cells.length > 0)
+ _loadCommitInfo(cells);
+ });
+}
+
+function loadCommitInfo() {
+ _loadCommitInfo( jQuery('#commit-tree .message').get() );
+}
+
+jQuery(function() {
+ // Provide sub-nav dropdowns (I think).
+ startList();
+
+ // JS up any Compare links
+ jQuery('a.compare-link').click(compareDiffs);
+ // Change the URL when a branch is selected
+ jQuery('#branch-list').change(switchBranch);
+ // Wait for image requests to come back first
+ jQuery(window).load(loadCommitInfo);
+});
+++ /dev/null
-[% PROCESS 'nav/actions.tt2' object = commit %]
-
-<div class='summary content'>
-<!-- <div id='stats'>
- <dt>Number of commits in the last day</dt><dd>N</dd>
- <dt>Most frequent commiter in the last week</dt><dd>Foo</dd>
- <dt>Hottest file in the repo</dt><dd>Bar.baz</dd>
- <dt>Current hue</dt><dd>either HEAD or some arbitrary munging</dd>
- </div> -->
-
- <dl>
- <dt>description</dt><dd>[% Repository.description %]</dd>
- <dt>owner</dt><dd>[% Repository.owner %]</dd>
- <dt>last change</dt><dd>[% Repository.last_change %]</dd>
- </dl>
-
- <h2><a href='[% c.uri_for("shortlog") %]'>shortlog</a></h2>
- [% INCLUDE '_shortlog.tt2' %]
-
- <h2><a href='[% c.uri_for("heads") %]'>branches</a></h2>
- [% INCLUDE '_heads.tt2' %]
-</div>
+++ /dev/null
-[% INCLUDE 'nav/actions.tt2' object = commit %]
-<div class='content'>
- <div>
- [% Repository.name %]
- </div>
-
- [% INCLUDE '_heads.tt2' heads = tags %]
-</div>
+++ /dev/null
-[% INCLUDE 'nav/actions.tt2' object = commit %]
-
-<div class='content'>
- <div class='commit-message'>
- [% short_cmt(commit.comment) | html %] ...
- </div>
-
- [%
- IF path;
- INCLUDE 'nav/path.tt2' filename = path, head = commit;
- END;
-
- INCLUDE '_tree.tt2';
- %]
-</div>
--- /dev/null
+[%- IF no_wrapper || template.name.match('\.(css|js|txt)'); content; ELSE; -%]
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <!-- git core binaries version [% git_version %] -->
+ <meta charset="utf-8" />
+ <meta name="generator" content="gitweb/[% version %] git/[% git_version %]" />
+ <meta name="robots" content="index, nofollow" />
+ <title>[%# FIXME - MING %][%-
+ title = BLOCK;
+ c.config.sitename;
+ IF Repository; ' - ' _ Repository.name | html; END;
+ IF c.action; ' / ' _ c.action; END;
+ IF filename; ' - ' _ filename | html; END;
+ IF c.action && c.action == 'tree'; '/'; END;
+ END;
+ title;
+ -%] (Gitalist)</title>
+ [% INCLUDE '_header_feeds.tt2' %]
+
+ <link rel="stylesheet" type="text/css" href="[% c.uri_for('/core.css') %]" />
+ <link rel="shortcut icon" href="[% c.uri_for('/static/favicon.ico') %]" />
+ <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
+ <script src="[% c.uri_for('/static/js/site.js') %]"></script>
+</head>
+
+<body>
+
+<div id="header_holder">
+ <div class="sub_holder">
+ <div id="header">
+ <a href="[% c.uri_for('/') %]" id="logo"><img src="[% c.uri_for('/static/i/logo.png') %]" alt="Gitalist" /></a>
+
+ <div class="search">
+ [% IF Repository; INCLUDE 'nav/search.tt2'; ELSE; %]
+
+ <!--
+ [%# FIXME - Search submits to blank(ish) page %]
+ <form method="get" action="[% c.uri_for_action('/search') %]" enctype="application/x-www-form-urlencoded">
+ <p class="projsearch">Search:
+ <input type="text" name="s" value="[% search_text %]" />
+ </p>
+ </form>
+ -->
+ [% END %]
+ </div>
+ </div>
+
+
+ <div id="nav_logs" [% 'style="visibility:hidden"' IF c.action.name == "index" %]>
+
+ [% IF c.req.captures.size == 1; SET path = 'repository'; ELSE; SET path = 'ref'; END %]
+
+ <ul>
+ <li[% ' class="selected"' IF c.action.name.match('tree') %]><a href="[% c.uri_for_action('/ref/tree', c.req.captures) || c.uri_for_action('/repository/tree', c.req.captures) %]" id="tree">Tree</a></li>
+
+ <li[% ' class="selected"' IF c.action.name.match('longlog') %]><a href="[% c.uri_for_action('/' _ path _ '/longlog', c.req.captures) %]" id="log_full">Long log</a></li>
+
+ <li[% ' class="selected"' IF c.action.name.match('shortlog') %]><a href="[% c.uri_for_action('/' _ path _ '/shortlog', c.req.captures) %]" id="log_short">Short log</a></li>
+
+
+ <li id="branch_selector">
+ Branches
+ <select id='branch-list'>
+ <option value="">HEAD</option>
+ [% FOREACH branch IN Repository.heads %]
+ <option value="[% branch.name %]">[% branch.name %]</option>
+ [% END %]
+
+ </select>
+ </li>
+
+ </ul>
+ </div>
+
+ <h1>
+ <a href="[% c.uri_for('/') %]">Home</a>
+
+ [%- IF Repository %]
+ / <a href="[% c.uri_for_action('/repository/summary', [Repository.name]) %]/shortlog">[% Repository.name %]</a>
+ [%- END %]
+ /
+ [%- IF Repository %]
+ [%# FIXME: output branch name in a nicer way!!! #%]
+ [% FOREACH branch_head IN Repository.heads %]
+ [% IF c.req.path.search(branch_head.name) %]
+ <a href="[% c.uri_for_action('/repository/summary', [Repository.name]) %]/[% branch_head.name %]/shortlog">[% branch_head.name %]</a> /
+ [% END %]
+ [% END %]
+ [%- END %]
+
+
+ [%-
+
+ #FIXME on a history view of a folder, don't show extra actions in dropdown
+ SET on_file_page = 1;
+
+ SET actions_list = {
+ "blob" => 1,
+ "raw" => 1,
+ "blame" => 1,
+ "history" => 1,
+ };
+
+ SET action_name = c.action.name
+ .replace("_"," ")
+ .replace("log", " log")
+ .replace("fancy","")
+ .replace("index","Repositories");
+ action_name_ucfirst = action_name FILTER ucfirst;
+ IF actions_list.$action_name && on_file_page;
+ '<a href="#" id="actions_nav_link"><span>' _ action_name_ucfirst _ '</span></a>';
+ ELSE;
+ action_name_ucfirst;
+ END;
+
+ -%]
+
+ </h1>
+
+ [%-
+ IF actions_list.$action_name;
+ '<ul id="actions_nav_list">';
+ FOREACH action IN actions_list;
+ action_output = action.key FILTER ucfirst;
+ NEXT IF action_output == action_name_ucfirst;
+ action = action.key;
+ '<li><a href="' _ c.uri_for("/") _ c.req.path.replace(action_name, action) _ '">' _ action_output _ '</a></li>';
+ END;
+ '</ul>';
+ END;
+ -%]
+
+ </div>
+</div>
+
+
+<div id="content_holder">
+ <div id="content" class="sub_holder">
+ <div id="content_inner">
+
+
+
+ [% content %]
+
+
+ </div>
+ </div>
+</div>
+
+<div id="footer_holder">
+ <div id="footer" class="sub_holder">
+
+ <p>[% IF Repository; Repository.description | html IF Repository.description != "Unnamed repository; edit this file to name it for gitweb." ; END; %]</p>
+
+ <a title="git homepage" href="http://git-scm.org"><img src="[% c.uri_for('/logo.png') %]" id="git_logo" alt="git" /></a>
+
+ <div id="feeds">
+ [% INCLUDE 'inc/footer_feeds.tt2' %]
+ </div>
+ </div>
+
+</div>
+
+
+
+<div id="debug_holder">
+ <div id="debug" class="sub_holder">
+
+ <p>Debug:</p>
+
+ [% USE Dumper %]
+ <pre>
+ [% Repository.path %]
+ [% Dumper.dump(c.req.args) %]
+ </pre>
+
+ </div>
+</div>
+
+<span id="current-uri" class="js-data">[%
+ # A bit of smoke and mirrors to get the /repository/shortlog URIs working
+ cur_act = '' _ c.action;
+ cur_uri = cur_act.match("log") || cur_act.match("^ref")
+ ? '/ref/' _ cur_act.replace("^(repository|ref)/", '')
+ : cur_act;
+ # XXX I just want lists!
+ IF c.req.args.size > 0;
+ c.uri_for_action(cur_uri, [Repository.name, 'HEAD'], c.req.args.0);
+ ELSE;
+ c.uri_for_action(cur_uri, [Repository.name, 'HEAD']);
+ END;
+%]</span>
+
+</body>
+</html>
+[%- END -%]
--- /dev/null
+#!/usr/bin/env perl
+
+# This script installs an initial local::lib into your application directory
+# named local-lib5, which automatically turns on local::lib support by default.
+
+# Needs to be run as script/bootstrap.pl
+
+# Will then install Module::Install, and all of your dependencies into
+# the local lib directory created.
+
+use strict;
+use warnings;
+
+use lib;
+use FindBin;
+use CPAN;
+
+# Do not take no for an answer.
+
+$ENV{CATALYST_LOCAL_LIB}=1;
+
+# Get the base paths and setup your %ENV
+
+my $basedir;
+if (-r "$FindBin::Bin/Makefile.PL") {
+ $basedir = $FindBin::Bin;
+}
+elsif (-r "$FindBin::Bin/../Makefile.PL") {
+ $basedir = "$FindBin::Bin/..";
+}
+
+$basedir ||= '';
+my $target = "$basedir/local-lib5";
+my $lib = "$target/lib/perl5";
+
+# Start installing stuff in the target dir
+$ENV{PERL_MM_OPT} = "INSTALL_BASE=$target";
+$ENV{PERL_MM_USE_DEFAULT} = "1";
+# And allow dependency checks to find it
+lib->import("$target/lib/perl5");
+
+# Deal with the weird case that cpan has never been run before and
+# cpan wants to create a .cpan directory in /root or somewhere you
+# can't access
+
+local %CPAN::Config;
+require CPAN::HandleConfig;
+CPAN::HandleConfig->load();
+$CPAN::Config->{prefs_dir} = "$ENV{HOME}/.cpan/prefs";
+
+force(qw/install local::lib/);
+
+require lib::core::only; # Turn lib::core:only on
+require local::lib; # Turn local::lib on
+lib::core::only->import();
+local::lib->import( $target );
+
+# Become fully self contained
+$ENV{PERL5LIB} = ""; # If we used a local::lib to bootstrap, this kills it.
+
+# Sorry kane ;)
+$ENV{PERL_AUTOINSTALL_PREFER_CPAN}=1;
+$ENV{PERL_MM_OPT} .= " INSTALLMAN1DIR=none INSTALLMAN3DIR=none";
+
+lib::core::only->import();
+local::lib->import( $target );
+
+# Force a re-install of local::lib here to get the dependencies for local::lib
+# It requires things which ensure we have an unfucked toolchain :)
+force(qw/install local::lib/);
+
+# Install the base modules
+install('Module::Install');
+install('YAML');
+install('CPAN');
+# For some reason this isn't installed along with M::I::Catalyst.
+install('File::Copy::Recursive');
+install('Module::Install::Catalyst');
+
+print "local::lib setup, type perl Makefile.PL && make installdeps to install dependencies";
+
--- /dev/null
+#!/usr/bin/env perl
+# vim: set filetype=perl:
+
+# env is a perl script similar in concept to /usr/bin/env
+
+# If you have a local-lib5 directory then this script will set it up for
+# you as it executes.
+
+# If used like /usr/bin/env then it will run other commands based on
+# your current path settings (with a local::lib environment if present)
+#
+# e.g. script/env bash
+#
+# NOTE: This environment _IS NOT_ self contained
+
+# If included inside another perl script, then it will be a no-op if
+# a local::lib environment is not present, but if one is, it will be
+# used as a --self-contained environment, expected to contain all non-core
+# dependencies for your perl
+#
+# e.g.
+# use FindBin;
+# BEGIN { do "$FindBin::Bin/env" or die $@ }
+
+# The local::lib behavior can be explicitly enabled or disabled by setting
+# the CATALYST_LOCAL_LIB enviromnent variable to true or false.
+
+use strict;
+use warnings;
+use Carp;
+use lib;
+use FindBin;
+
+my $basedir;
+if (-r "$FindBin::Bin/Makefile.PL") {
+ $basedir = $FindBin::Bin;
+}
+elsif (-r "$FindBin::Bin/../Makefile.PL") {
+ $basedir = "$FindBin::Bin/..";
+}
+
+$basedir ||= '';
+my $target = "$basedir/local-lib5";
+
+my $on = -d $target;
+$on = ! ! $ENV{CATALYST_LOCAL_LIB}
+ if (exists $ENV{CATALYST_LOCAL_LIB} and defined $ENV{CATALYST_LOCAL_LIB});
+
+Carp::confess("Could not find local-lib5 from '$FindBin::Bin'")
+ if ($on && ! length $basedir);
+
+if ( $on ) {
+ # So we can find local::lib when fully self contained
+ lib->import("$target/lib/perl5");
+
+ # . for CPAN + app dir
+ my @include = ('.', "$basedir/lib");
+
+ $ENV{PERL5LIB} = join ':', @include;
+
+ # Sorry kane ;)
+ $ENV{PERL_AUTOINSTALL_PREFER_CPAN}=1;
+
+ $ENV{PERL_MM_OPT} .= " INSTALLMAN1DIR=none INSTALLMAN3DIR=none";
+
+ require lib::core::only;
+ require local::lib;
+ lib::core::only->import();
+ local::lib->import( $target );
+}
+
+unless ( caller ) {
+ if ( @ARGV ) {
+ exec @ARGV;
+ }
+}
+
+1;
+
#!/usr/bin/env perl
+use FindBin;
+BEGIN { do "$FindBin::Bin/env" or die $@ }
+
use Catalyst::ScriptRunner;
Catalyst::ScriptRunner->run('Gitalist', 'CGI');
#!/usr/bin/env perl
+use FindBin;
+BEGIN { do "$FindBin::Bin/env" or die $@ }
use strict;
use warnings;
#!/usr/bin/env perl
+use FindBin;
+BEGIN { do "$FindBin::Bin/env" or die $@ }
use Catalyst::ScriptRunner;
Catalyst::ScriptRunner->run('Gitalist','FastCGI');
#!/usr/bin/env perl
+use FindBin;
+BEGIN { do "$FindBin::Bin/env" or die $@ }
BEGIN {
$ENV{CATALYST_SCRIPT_GEN} = 40;
#!/usr/bin/env perl
+use FindBin;
+BEGIN { do "$FindBin::Bin/env" or die $@ }
use Catalyst::ScriptRunner;
Catalyst::ScriptRunner->run('Gitalist','Test');
#!/usr/bin/env perl
-use strict;
-use warnings;
-use Test::More;
use FindBin qw/$Bin/;
-
-BEGIN {
- $ENV{GITALIST_CONFIG} = $Bin;
- $ENV{GITALIST_REPO_DIR} = '';
- use_ok 'Catalyst::Test', 'Gitalist';
-}
-
-ok( request('/')->is_success, 'Request should succeed' );
-
-for my $p (qw/ repo1 nodescription /) {
- my $path = '/summary?p=' . $p;
+use lib "$Bin/lib";
+use TestGitalist;
+
+for my $p ('', qw{
+ repo1 nodescription bare.git opml search
+ fragment/collectionofrepositories
+}) {
+ my $path = '/' . $p;
ok( request($path)->is_success, "$path should succeed");
}
-my $response = request('/summary?p=DoesNotExist');
+my $response = request('/DoesNotExist');
is $response->code, 404, 'invalid repository 404s';
like $response->content, qr/Page not found/, 'invalid repository handled correctly';
-is request('/summary?p=../../../')->code, 404, 'directory traversal failed';
+# URI tests for repo1
+foreach my $test (map {curry_test_uri($_)} ('fragment/repo1', 'repo1') ) {
+ $test->('');
+ $test->('shortlog');
+ $test->('log');
+ $test->('heads');
+ $test->('tags');
+ $test->('36c6c6708b8360d7023e8a1649c45bcf9b3bd818');
+ $test->('36c6c6708b8360d7023e8a1649c45bcf9b3bd818/tree');
+ $test->('36c6c6708b8360d7023e8a1649c45bcf9b3bd818/tree/dir1');
+ $test->('36c6c6708b8360d7023e8a1649c45bcf9b3bd818/diff');
+ $test->('36c6c6708b8360d7023e8a1649c45bcf9b3bd818/diff/plain');
+ $test->('36c6c6708b8360d7023e8a1649c45bcf9b3bd818/history/dir1');
+ $test->('36c6c6708b8360d7023e8a1649c45bcf9b3bd818/history/dir1');
+ $test->('36c6c6708b8360d7023e8a1649c45bcf9b3bd818/blame/file1');
+ $test->('36c6c6708b8360d7023e8a1649c45bcf9b3bd818/blob/file1');
+}
{
# URI tests for repo1
local *test = curry_test_uri('repo1');
- test('/summary');
- test('/shortlog');
- test('/log');
- test('/reflog');
- test('/commit');
- test('/commitdiff', 'h=36c6c6708b8360d7023e8a1649c45bcf9b3bd818');
- test('/tree', 'h=145dc3ef5d307be84cb9b325d70bd08aeed0eceb;hb=36c6c6708b8360d7023e8a1649c45bcf9b3bd818');
- test('/search', 'h=36c6c6708b8360d7023e8a1649c45bcf9b3bd818&f=&type=commit&text=added');
- test('/blobdiff', 'f=file1;h=5716ca5987cbf97d6bb54920bea6adde242d87e6;hp=257cc5642cb1a054f08cc83f2d943e56fd3ebe99;hb=refs/heads/master;hpb=3bc0634310b9c62222bb0e724c11ffdfb297b4ac');
- test('/blob', 'f=dir1/file2;hb=36c6c6708b8360d7023e8a1649c45bcf9b3bd818');
- test('/patch');
- test('/patch', 'h=3f7567c7bdf7e7ebf410926493b92d398333116e');
- test('/patch', 'h=3f7567c7bdf7e7ebf410926493b92d398333116e;hp=3bc0634310b9c62222bb0e724c11ffdfb297b4ac');
- test('/patches');
- test('/patches', 'h=3f7567c7bdf7e7ebf410926493b92d398333116e');
- test('/patches', 'h=3f7567c7bdf7e7ebf410926493b92d398333116e;hp=3bc0634310b9c62222bb0e724c11ffdfb297b4ac');
+ test('search');
+
+ test('36c6c6708b8360d7023e8a1649c45bcf9b3bd818/patch');
+ test('36c6c6708b8360d7023e8a1649c45bcf9b3bd818/patches/1');
+ test('36c6c6708b8360d7023e8a1649c45bcf9b3bd818/patches/2');
+ test('36c6c6708b8360d7023e8a1649c45bcf9b3bd818/raw/file1');
+
+ TODO: {
+ local $TODO = "FIXME";
+ test('search', 'type=commit&text=added');
+
+ # FIXME - What's the difference here?
+ #test('patch', 'h=3f7567c7bdf7e7ebf410926493b92d398333116e');
+ #test('patch', 'h=3f7567c7bdf7e7ebf410926493b92d398333116e;hp=3bc0634310b9c62222bb0e724c11ffdfb297b4ac');
+ #test('patches', 'h=3f7567c7bdf7e7ebf410926493b92d398333116e');
+ #test('patches', 'h=3f7567c7bdf7e7ebf410926493b92d398333116e;hp=3bc0634310b9c62222bb0e724c11ffdfb297b4ac');
+ }
}
done_testing;
-
-sub test_uri {
- my ($p, $uri, $qs) = @_;
- $qs ||= '';
- my $request = "$uri?p=repo1;$qs";
- my $response = request($request);
- ok($response->is_success, "ok $p - $uri - $qs");
-}
-
-sub curry_test_uri {
- my $p = shift;
- sub {
- my ($uri, $qs) = @_;
- test_uri($p, $uri, $qs);
- };
-};
isa_ok($commit_obj, 'Gitalist::Git::Object::Commit', "commit object");
my ($tree, $patch) = $commit_obj->diff(
parent => undef,
- file => undef,
+ filename => undef,
patch => 1,
);
$patch = $patch->[0];
#!/usr/bin/env perl
-use strict;
-use warnings;
-use Test::More;
use FindBin qw/$Bin/;
-
-BEGIN {
- $ENV{GITALIST_CONFIG} = $Bin;
- no warnings;
- $ENV{GITALIST_REPO_DIR} = undef;
- use warnings;
- use_ok 'Catalyst::Test', 'Gitalist';
-}
+use lib "$Bin/lib";
+use TestGitalist qw/request curry_test_uri done_testing ok is $TODO/;
ok( request('/')->is_success, 'Request should succeed' );
+sub test {
+ my ($uri, $qs) = @_;
+ my $request = "/$uri";
+ $request =~ s{/+}{/}g;
+ $request .= "?$qs" if defined $qs;
+ my $response = request($request);
+ $uri = $response->header('Location') || '';
+ is($response->code, 301, "ok $request 301 to " . $uri)
+ or return $response;
+ $response = request($uri);
+ ok($response->is_success, "ok $uri");
+ return $response;
+}
+# FIXME
# URI tests for repo1
-local *test = curry_test_uri('repo1');
+#local *test = curry_test_uri('repo1');
+
+test('/', 'a=project_index');
+test('/', 'a=opml');
+no warnings 'redefine';
+local *test = curry_test_uri('repo1', \&test);
+test('/', 'a=project_index');
+test('/', 'a=opml');
test('/', 'a=summary');
test('/', 'a=heads');
test('/', 'a=tags');
test('/', 'a=blob_plain;f=file1;hb=master');
test('/', 'a=blob_plain;f=file1;hb=refs/heads/master');
+
test('/', 'a=blobdiff;f=file1;h=5716ca5987cbf97d6bb54920bea6adde242d87e6;hp=257cc5642cb1a054f08cc83f2d943e56fd3ebe99;hb=36c6c6708b8360d7023e8a1649c45bcf9b3bd818;hpb=3bc0634310b9c62222bb0e724c11ffdfb297b4ac');
test('/', 'a=blobdiff;f=file1;h=5716ca5987cbf97d6bb54920bea6adde242d87e6;hp=257cc5642cb1a054f08cc83f2d943e56fd3ebe99;hb=3f7567c7bdf7e7ebf410926493b92d398333116e;hpb=3bc0634310b9c62222bb0e724c11ffdfb297b4ac');
test('/', 'a=blobdiff;f=file1;h=5716ca5987cbf97d6bb54920bea6adde242d87e6;hp=257cc5642cb1a054f08cc83f2d943e56fd3ebe99;hb=HEAD;hpb=3bc0634310b9c62222bb0e724c11ffdfb297b4ac');
test('/', 'a=commitdiff_plain;h=refs/heads/master');
test('/', 'a=commitdiff_plain;h=refs/heads/master;hp=3f7567c7bdf7e7ebf410926493b92d398333116e');
-
test('/', 'a=history;f=dir1/file2;h=257cc5642cb1a054f08cc83f2d943e56fd3ebe99;hb=36c6c6708b8360d7023e8a1649c45bcf9b3bd818');
test('/', 'a=history;f=dir1/file2;h=257cc5642cb1a054f08cc83f2d943e56fd3ebe99;hb=HEAD');
test('/', 'a=history;f=dir1/file2;h=257cc5642cb1a054f08cc83f2d943e56fd3ebe99;hb=master');
test('/', 'a=tree;hb=master');
test('/', 'a=tree;hb=refs/heads/master');
-
test('/', 'a=atom');
test('/', 'a=atom;f=dir1');
test('/', 'a=atom;f=dir1/file2');
test('/', 'a=rss;h=refs/heads/master;opt=--no-merges');
test('/', 'a=rss;opt=--no-merges');
-test('/', 'a=project_index');
-
-test('/', 'a=opml');
-
test('/', 'a=blame;f=dir1/file2;hb=36c6c6708b8360d7023e8a1649c45bcf9b3bd818');
test('/', 'a=blame;f=file1;h=257cc5642cb1a054f08cc83f2d943e56fd3ebe99;hb=3bc0634310b9c62222bb0e724c11ffdfb297b4ac');
test('/', 'a=blame;f=file1;h=5716ca5987cbf97d6bb54920bea6adde242d87e6;hb=36c6c6708b8360d7023e8a1649c45bcf9b3bd818');
test('/', 'a=blame;f=file1;hb=3f7567c7bdf7e7ebf410926493b92d398333116e');
done_testing;
-
-sub test_uri {
- my ($p, $uri, $qs) = @_;
- $qs ||= '';
- my $request = "$uri?p=repo1;$qs";
- my $response = request($request);
- ok($response->is_success, "ok $request");
-}
-
-sub curry_test_uri {
- my $p = shift;
- sub {
- my ($uri, $qs) = @_;
- test_uri($p, $uri, $qs);
- };
-};
--- /dev/null
+#!/usr/bin/env perl
+use FindBin qw/$Bin/;
+use lib "$Bin/lib";
+use TestGitalist;
+plan 'skip_all' => "One or more of the following modules aren't present: Test::WWW::Mechanize::Catalyst WWW::Mechanize::TreeBuilder HTML::TreeBuilder::XPath" unless MECH();
+
+MECH->get_ok('/');
+{
+ my $nodeset = MECH->findnodes('/html/body//tr[@class="reposrow"]');
+ foreach my $row ($nodeset->get_nodelist) {
+ my $uri = $row->findnodes('.//a')->[0]->attr('href');
+ my ($repos_name) = $uri =~ m{^http://localhost/([\w\.]+)$};
+ ok $repos_name, "Repos name $repos_name";
+ like $row->findnodes('.//a')->[1]->as_text, qr{^[\w\s/;',\.]+$}, 'Have description'
+ unless $repos_name eq 'nodescription';
+ like $row->findnodes('.//td[@class="time-since"')->[0]->as_text, qr/^(never|\d\s+(years|months)\s+ago)$/,
+ 'Last change looks ok';
+ my ($summary, $shortlog, $log, $tree) = $row->findnodes('.//td[@class="link"]/a')->get_nodelist;
+ like $summary->as_text, qr/summary/i, 'summary text ok';
+ is $summary->attr('href'), $uri, 'summary href correct';
+ like $shortlog->as_text, qr/shortlog/i, 'shortlog text ok';
+ is $shortlog->attr('href'), "$uri/shortlog", 'shortlog href ok';
+ like $log->as_text, qr/log/, 'log text ok';
+ is $log->attr('href'), "$uri/log", 'log href ok';
+ like $tree->as_text, qr/tree/, 'tree text ok';
+ TODO: {
+ local $TODO = 'Bork';
+ is $tree->attr('href'), "$uri/tree", 'tree href ok';
+ }
+ }
+}
+
+done_testing;
--- /dev/null
+#!/usr/bin/env perl
+use FindBin qw/$Bin/;
+use lib "$Bin/lib";
+use TestGitalist;
+
+my $res = request('/repo1/atom');
+ok $res->is_success;
+is $res->content_type, 'application/atom+xml';
+TODO: {
+ local $TODO = "Does not work yet. Need similar info to RSS feed";
+ like $res->content, qr{link>http://localhost/repo1</link};
+ like $res->content, qr{description>some test repository</description};
+}
+like $res->content, qr{add dir1/file2</div};
+like $res->content, qr{<id>http://localhost/repo1/36c6c6708b8360d7023e8a1649c45bcf9b3bd818/commit</id};
+like $res->content, qr{title>add dir1/file2</title};
+
+done_testing;
-<Model::GitRepos>
+<Model::CollectionOfRepos>
repo_dir __path_to(t/lib/repositories)__
-</Model::GitRepos>
+</Model::CollectionOfRepos>
name Gitalist
--- /dev/null
+package TestGitalist;
+use strict;
+use warnings;
+use Exporter ();
+use FindBin qw/$Bin/;
+BEGIN {
+ $ENV{GITALIST_CONFIG} = $Bin;
+ $ENV{GITALIST_REPO_DIR} = '';
+}
+use Catalyst::Test qw/Gitalist/;
+use Test::More;
+use Test::Exception;
+
+our @EXPORT = (@Test::More::EXPORT, @Test::Exception::EXPORT, qw/
+ test_uri
+ curry_test_uri
+ MECH
+ request
+ get
+ ctx_request
+ content_like
+ action_ok
+ action_redirect
+ action_notfound
+ contenttype_is
+/);
+
+sub import {
+ my $into = caller();
+ strict->import;
+ warnings->import;
+ goto \&Exporter::import;
+}
+
+use constant ();
+BEGIN {
+ my $mech = eval {
+ require Test::WWW::Mechanize::Catalyst;
+ require WWW::Mechanize::TreeBuilder;
+ my $mech = Test::WWW::Mechanize::Catalyst->new(catalyst_app => 'Gitalist');
+ WWW::Mechanize::TreeBuilder->meta->apply($mech,
+ tree_class => 'HTML::TreeBuilder::XPath',
+ );
+ return $mech;
+ };
+ constant->import('MECH', $mech );
+}
+
+# Rechecking the same link multiple times is slow and lame!
+# Nicked this from WWW::Mechanize and memoized it...
+my %seen_links;
+sub Test::WWW::Mechanize::Catalyst::page_links_ok {
+ my $self = shift;
+ my $desc = shift;
+
+ $desc = 'All links ok' unless defined $desc;
+
+ my @links = $self->followable_links();
+ my @urls = Test::WWW::Mechanize::_format_links(\@links);
+
+ my @failures = $self->_check_links_status( [ grep { ! $seen_links{$_}++ } @urls ] );
+ my $ok = (@failures==0);
+
+ ok( $ok, $desc );
+ diag( $_ ) for @failures;
+
+ return $ok;
+}
+
+
+sub test_uri {
+ my ($uri, $qs) = @_;
+ my $request = "/$uri";
+ $request .= "?$qs" if defined $qs;
+ my $response = request($request);
+ ok($response->is_success || $response->is_redirect, "ok $request");
+ if (MECH) {
+ my $res = MECH()->get($request);
+ ok $res->is_success, "ok mech $request (" . $res->code . ')';
+ MECH()->page_links_ok("All links ok from $request")
+ if $res->content_type =~ m|text/html|;
+ }
+ return $response;
+}
+
+sub curry_test_uri {
+ my $prefix = shift;
+ my $to_curry = shift || \&test_uri;
+ sub {
+ my $uri = shift;
+ $to_curry->("$prefix/$uri", @_);
+ };
+}
+
+1;
+++ /dev/null
-name Gitalist
-
-#git /path/to/git
-projectroot __path_to(t/lib/repositories)__
-repo_dir __path_to(t/lib/repositories)__
-
-sitename "Gitalist presently"
-
-# URI and label (title) of GIT logo link
-logo_url git-scm.org
-logo_label "git homepage"
-logo_img /git-logo.png
-
-home_link /
-home_link_str "A Gitalist"
-
-# XXX let's not hardcode these yeah?
-version 1.6.3.3
-
-# show repository only if this file exists
-# (only effective if this variable evaluates to true)
-# export_ok
-
-# XXX Code in config FAIL
-# show repository only if this subroutine returns true
-# when given the path to the project, for example:
-# sub { return -e "$_[0]/git-daemon-export-ok"; }
-# export_auth_hook
-
-# stylesheet path/to/your/stylesheet.css
-logo /git-logo.png
-favicon /git-favicon.png
-
-# $feature{'blame'}{'default'} = [1];
-<feature>
- <blame>
- default = 1
- </blame>
-</feature>
-
-# fs traversing limit for getting project list
-# the number is relative to the projectroot
-project_maxdepth 2007
--- /dev/null
+36c6c6708b8360d7023e8a1649c45bcf9b3bd818
use Catalyst::Request;
use Catalyst::Response;
use Catalyst::Utils;
-use Gitalist::Model::GitRepos;
+use Gitalist::Model::CollectionOfRepos;
use File::Temp qw/tempdir/;
-
+
my $mock_ctx_meta = Class::MOP::Class->create_anon_class( superclasses => ['Moose::Object'] );
$mock_ctx_meta->add_attribute($_, accessor => $_, required => 1) for qw/request response/;
$mock_ctx_meta->add_attribute('stash', accessor => 'stash', required => 1, default => sub { {} });
local %ENV = %ENV;
delete $ENV{GITALIST_REPO_DIR};
-throws_ok { Gitalist::Model::GitRepos->COMPONENT($ctx_gen->(), {}) }
+throws_ok { Gitalist::Model::CollectionOfRepos->COMPONENT($ctx_gen->(), {}) }
qr/Cannot find repository dir/, 'Blows up nicely with no repos dir';
-throws_ok { Gitalist::Model::GitRepos->COMPONENT($ctx_gen->(), { repo_dir => '/does/not/exist' }) }
+throws_ok { Gitalist::Model::CollectionOfRepos->COMPONENT($ctx_gen->(), { repo_dir => '/does/not/exist' }) }
qr|Cannot find repository dir: "/does/not/exist"|, 'Blows up nicely with repos dir does not exist';
{
}
# Note - we treat an empty list of repos as if it doesn't exist at all.
-throws_ok { Gitalist::Model::GitRepos->COMPONENT($ctx_gen->(), { repos => [] } ) }
+throws_ok { Gitalist::Model::CollectionOfRepos->COMPONENT($ctx_gen->(), { repos => [] } ) }
qr/Cannot find repository dir/, 'Blows up nicely with no repos list';
-throws_ok { Gitalist::Model::GitRepos->COMPONENT($ctx_gen->(), { repos => [ '/does/not/exist' ] } ) }
+throws_ok { Gitalist::Model::CollectionOfRepos->COMPONENT($ctx_gen->(), { repos => [ '/does/not/exist' ] } ) }
qr/Cannot find repository directories/, 'Blows up nicely with repos list - 1 unknown item (array)';
-throws_ok { Gitalist::Model::GitRepos->COMPONENT($ctx_gen->(), { repos => '/does/not/exist' } ) }
+throws_ok { Gitalist::Model::CollectionOfRepos->COMPONENT($ctx_gen->(), { repos => '/does/not/exist' } ) }
qr/Cannot find repository directories/, 'Blows up nicely with repos list - 1 unknown item (scalar))';
-throws_ok { Gitalist::Model::GitRepos->COMPONENT($ctx_gen->(), { repos => [ '/does/not/exist', '/also/does/not/exist' ] } ) }
+throws_ok { Gitalist::Model::CollectionOfRepos->COMPONENT($ctx_gen->(), { repos => [ '/does/not/exist', '/also/does/not/exist' ] } ) }
qr/Cannot find repository directories/, 'Blows up nicely with repos list - 2 unknown items';
-throws_ok { Gitalist::Model::GitRepos->COMPONENT($ctx_gen->(), { repos => [ tempdir( CLEANUP => 1), '/also/does/not/exist' ] } ) }
+throws_ok { Gitalist::Model::CollectionOfRepos->COMPONENT($ctx_gen->(), { repos => [ tempdir( CLEANUP => 1), '/also/does/not/exist' ] } ) }
qr|Cannot find repository directories.*/also/does/not/exist|, 'Blows up nicely with repos list - 1 known, 1 unknown items';
{
my $td = tempdir( CLEANUP => 1 );
local %ENV = %ENV;
$ENV{GITALIST_REPO_DIR} = $td;
- lives_ok { Gitalist::Model::GitRepos->COMPONENT($ctx_gen->(), {}) } 'GITALIST_REPO_DIR env variable works';
+ lives_ok { Gitalist::Model::CollectionOfRepos->COMPONENT($ctx_gen->(), {}) } 'GITALIST_REPO_DIR env variable works';
}
{
my $ctx = $ctx_gen->();
my $m;
- lives_ok { $m = Gitalist::Model::GitRepos->COMPONENT($ctx, $config) } $msg;
+ lives_ok { $m = Gitalist::Model::CollectionOfRepos->COMPONENT($ctx, $config) } $msg;
ok $m, 'Has model';
my $i = $m->ACCEPT_CONTEXT($ctx);
ok $i, 'Has model instance from ACCEPT_CONTEXT';
--- /dev/null
+#!/usr/bin/env perl
+use FindBin qw/$Bin/;
+use lib "$Bin/lib";
+use TestGitalist;
+
+my $res = request('/opml');
+ok $res->is_success;
+
+is $res->content_type, 'application/rss';
+like $res->content, qr{Gitalist</title>};
+like $res->content, qr{xmlUrl="http://localhost/bare.git/rss"};
+like $res->content, qr{text="repo1 - some test repository"};
+like $res->content, qr{xmlUrl="http://localhost/repo1/rss"};
+
+done_testing;
--- /dev/null
+#!/usr/bin/env perl
+use FindBin qw/$Bin/;
+use lib "$Bin/lib";
+use TestGitalist;
+
+my $res = request('/repo1/rss');
+ok $res->is_success;
+is $res->content_type, 'application/rss+xml';
+like $res->content, qr{link>http://localhost/repo1</link};
+like $res->content, qr{description>some test repository</description};
+like $res->content, qr{title>add dir1/file2</title};
+like $res->content, qr{description>add dir1/file2</description};
+like $res->content, qr{guid isPermaLink="true">http://localhost/repo1/36c6c6708b8360d7023e8a1649c45bcf9b3bd818/commit</guid};
+
+done_testing;
--- /dev/null
+#!/usr/bin/env perl
+
+use FindBin qw/$Bin/;
+use lib "$Bin/../../lib";
+
+BEGIN {
+ $ENV{GITALIST_CONFIG} = "$Bin/../gitalist.conf";
+}
+
+use Catalyst::ScriptRunner;
+Catalyst::ScriptRunner->run('Gitalist', 'Server');
+
+1;
+