Merge remote branch 't0m/json' into json
Dan Brook [Sun, 2 May 2010 19:06:51 +0000 (20:06 +0100)]
Conflicts:
Makefile.PL
lib/Gitalist/Controller/Root.pm
lib/Gitalist/Git/Repository.pm

166 files changed:
.gitignore
Changes
ISSUES
Makefile.PL
README
gitalist.conf
gitalist_local.conf
lib/Gitalist.pm
lib/Gitalist/ActionRole/FilenameArgs.pm [new file with mode: 0644]
lib/Gitalist/ContentMangler/Resolver.pm [new file with mode: 0644]
lib/Gitalist/ContentMangler/Resolver/Default.pm [new file with mode: 0644]
lib/Gitalist/Controller.pm [new file with mode: 0644]
lib/Gitalist/Controller/Fragment.pm [new file with mode: 0644]
lib/Gitalist/Controller/Fragment/Ref.pm [new file with mode: 0644]
lib/Gitalist/Controller/Fragment/Repository.pm [new file with mode: 0644]
lib/Gitalist/Controller/LegacyURI.pm [new file with mode: 0644]
lib/Gitalist/Controller/OPML.pm [new file with mode: 0644]
lib/Gitalist/Controller/Ref.pm [new file with mode: 0644]
lib/Gitalist/Controller/Repository.pm [new file with mode: 0644]
lib/Gitalist/Controller/Root.pm
lib/Gitalist/Git/Object/Commit.pm
lib/Gitalist/Git/Repository.pm
lib/Gitalist/Model/CollectionOfRepos.pm [moved from lib/Gitalist/Model/GitRepos.pm with 98% similarity]
lib/Gitalist/Model/ContentMangler.pm [new file with mode: 0644]
lib/Gitalist/URIStructure/Fragment/WithLog.pm [new file with mode: 0644]
lib/Gitalist/URIStructure/Ref.pm [new file with mode: 0644]
lib/Gitalist/URIStructure/Repository.pm [new file with mode: 0644]
lib/Gitalist/URIStructure/WithLog.pm [new file with mode: 0644]
lib/Gitalist/Utils.pm
lib/Gitalist/View/Default.pm
lib/Gitalist/View/SyntaxHighlight.pm
root/_chroma_hash.tt2 [deleted file]
root/_diff.tt2 [changed mode: 0644->0755]
root/_diff_tree.tt2 [changed mode: 0644->0755]
root/_header_feeds.tt2
root/_heads.tt2 [deleted file]
root/_history.tt2 [deleted file]
root/_log_pager.tt2
root/_refs.tt2
root/_shortlog.tt2 [deleted file]
root/_tree.tt2 [deleted file]
root/blame.tt2 [deleted file]
root/blob.tt2 [deleted file]
root/blobdiff.tt2 [deleted file]
root/blobdiff_plain.tt2 [deleted file]
root/commit.tt2 [deleted file]
root/commitdiff.tt2 [deleted file]
root/commitdiff_plain.tt2 [deleted file]
root/default.tt2 [deleted file]
root/favicon.ico [changed mode: 0644->0755]
root/favicon.png [deleted file]
root/fragment/collectionofrepositories.tt2 [new file with mode: 0755]
root/fragment/ref/blame.tt2 [new file with mode: 0755]
root/fragment/ref/blob.tt2 [new file with mode: 0644]
root/fragment/ref/commit.tt2 [new file with mode: 0755]
root/fragment/ref/diff_fancy.tt2 [new file with mode: 0755]
root/fragment/ref/diff_plain.tt2 [new file with mode: 0644]
root/fragment/ref/history.tt2 [new file with mode: 0755]
root/fragment/ref/longlog.tt2 [new file with mode: 0644]
root/fragment/ref/shortlog.tt2 [new file with mode: 0644]
root/fragment/ref/tree.tt2 [new file with mode: 0755]
root/fragment/repository/heads.tt2 [new file with mode: 0755]
root/fragment/repository/longlog.tt2 [new file with mode: 0755]
root/fragment/repository/shortlog.tt2 [new file with mode: 0755]
root/fragment/repository/summary.tt2 [new file with mode: 0755]
root/fragment/repository/tags.tt2 [new file with mode: 0644]
root/git-logo.png [deleted file]
root/gitweb.css [deleted file]
root/gitweb.tt2 [deleted file]
root/heads.tt2 [deleted file]
root/history.tt2 [deleted file]
root/inc/chroma_hash.tt2 [new file with mode: 0755]
root/inc/footer_feeds.tt2 [moved from root/_footer_feeds.tt2 with 74% similarity]
root/inc/log_pager.tt2 [new file with mode: 0755]
root/inc/syntax_highlight_css.tt2
root/index.tt2 [changed mode: 0644->0755]
root/log.tt2 [deleted file]
root/logo.svg [deleted file]
root/nav/actions.tt2
root/nav/path.tt2 [changed mode: 0644->0755]
root/nav/search.tt2 [changed mode: 0644->0755]
root/opml.tt2 [new file with mode: 0644]
root/ref/blame.tt2 [new file with mode: 0755]
root/ref/blob.tt2 [new file with mode: 0755]
root/ref/commit.tt2 [new file with mode: 0644]
root/ref/diff_fancy.tt2 [new file with mode: 0755]
root/ref/diff_plain.tt2 [new file with mode: 0644]
root/ref/history.tt2 [new file with mode: 0644]
root/ref/longlog.tt2 [new file with mode: 0644]
root/ref/shortlog.tt2 [new file with mode: 0644]
root/ref/tree.tt2 [new file with mode: 0755]
root/repository/atom.tt2 [new file with mode: 0644]
root/repository/heads.tt2 [new file with mode: 0644]
root/repository/longlog.tt2 [new file with mode: 0644]
root/repository/reflog.tt2 [moved from root/reflog.tt2 with 100% similarity]
root/repository/rss.tt2 [new file with mode: 0644]
root/repository/search.tt2 [new file with mode: 0755]
root/repository/shortlog.tt2 [new file with mode: 0755]
root/repository/summary.tt2 [new file with mode: 0755]
root/repository/tags.tt2 [new file with mode: 0755]
root/search.tt2 [changed mode: 0644->0755]
root/search_help.tt2 [changed mode: 0644->0755]
root/shortlog.tt2 [deleted file]
root/static/css/blueprint/ie.css [deleted file]
root/static/css/blueprint/print.css [deleted file]
root/static/css/blueprint/screen.css [deleted file]
root/static/css/core.css [new file with mode: 0755]
root/static/css/site.css [deleted file]
root/static/css/syntax/Diff.css [changed mode: 0644->0755]
root/static/favicon.ico [new file with mode: 0755]
root/static/git-favicon.png [moved from root/git-favicon.png with 100% similarity]
root/static/i/arrow_down_white.gif [new file with mode: 0755]
root/static/i/arrow_grey.gif [new file with mode: 0755]
root/static/i/arrow_grey_left.gif [new file with mode: 0755]
root/static/i/bg.png [new file with mode: 0755]
root/static/i/bg_bottom.png [new file with mode: 0755]
root/static/i/bg_content.png [new file with mode: 0755]
root/static/i/bg_top.png [new file with mode: 0755]
root/static/i/buttons/search.png [new file with mode: 0755]
root/static/i/favicon.gif [new file with mode: 0755]
root/static/i/favicon.png [new file with mode: 0755]
root/static/i/icons/Thumbs.db [new file with mode: 0644]
root/static/i/icons/attention.png [new file with mode: 0755]
root/static/i/icons/blame.png [new file with mode: 0755]
root/static/i/icons/blob.png [new file with mode: 0755]
root/static/i/icons/button_sha1.png [new file with mode: 0755]
root/static/i/icons/button_sha1_invert.png [new file with mode: 0755]
root/static/i/icons/commit.png [new file with mode: 0755]
root/static/i/icons/diff.png [new file with mode: 0755]
root/static/i/icons/diffcurrent.png [new file with mode: 0755]
root/static/i/icons/file.png [new file with mode: 0755]
root/static/i/icons/folder.png [new file with mode: 0755]
root/static/i/icons/fulllog.gif [new file with mode: 0755]
root/static/i/icons/history.png [new file with mode: 0755]
root/static/i/icons/longlog.png [new file with mode: 0755]
root/static/i/icons/raw.png [new file with mode: 0755]
root/static/i/icons/shortlog.gif [new file with mode: 0755]
root/static/i/icons/shortlog.png [new file with mode: 0755]
root/static/i/icons/tree.gif [new file with mode: 0755]
root/static/i/icons/tree.png [new file with mode: 0755]
root/static/i/logo.png [new file with mode: 0755]
root/static/js/site.js [new file with mode: 0755]
root/summary.tt2 [deleted file]
root/tags.tt2 [deleted file]
root/tree.tt2 [deleted file]
root/wrapper.tt2 [new file with mode: 0755]
script/bootstrap.pl [new file with mode: 0644]
script/env [new file with mode: 0755]
script/gitalist_cgi.pl
script/gitalist_create.pl
script/gitalist_fastcgi.pl
script/gitalist_server.pl
script/gitalist_test.pl
t/01app.t
t/02git_object.t
t/03legacy_uri.t
t/app-mech-rootpage.t [new file with mode: 0644]
t/atom.t [new file with mode: 0644]
t/gitalist.conf
t/lib/TestGitalist.pm [new file with mode: 0644]
t/lib/gitalist_testing.conf [deleted file]
t/lib/repositories/repo1/refs/tags/0.01 [new file with mode: 0644]
t/model_collectionofrepos.t [moved from t/model_gitrepos.t with 77% similarity]
t/opml.t [new file with mode: 0644]
t/rss.t [new file with mode: 0644]
t/script/gitalist_server.pl [new file with mode: 0755]

index b23a01a..ccafab4 100644 (file)
@@ -1,3 +1,4 @@
+Thumbs.db
 Gitalist-*
 *.swp
 git-daemon-export-ok
@@ -7,7 +8,6 @@ META.yml
 Makefile
 Makefile.old
 blib*
-inc*
 pm_to_blib
 MANIFEST
 MANIFEST.bak
diff --git a/Changes b/Changes
index 90280a8..4488bb5 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,6 +1,42 @@
 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.
@@ -23,6 +59,7 @@ This file documents the revision history for Perl extension Gitalist.
     - 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
@@ -30,7 +67,6 @@ This file documents the revision history for Perl extension Gitalist.
     - 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
diff --git a/ISSUES b/ISSUES
index 057c37d..74d64a7 100644 (file)
--- a/ISSUES
+++ b/ISSUES
@@ -1,3 +1,7 @@
+* 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).
index 9bac265..54e0b01 100644 (file)
@@ -1,5 +1,8 @@
 #!/usr/bin/env perl
 
+use FindBin;
+BEGIN { do "$FindBin::Bin/script/env" or die $@ }
+
 use strict;
 use warnings;
 
@@ -29,7 +32,7 @@ if ($ENV{GITALIST_RELEASE_TESTING}) {
     # 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);
 
@@ -54,9 +57,13 @@ requires 'Catalyst::Plugin::ConfigLoader';
 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';
@@ -67,6 +74,7 @@ requires 'Config::General';
 
 requires 'Moose';
 requires 'Moose::Autobox';
+requires 'MooseX::MultiMethods' => '0.10';
 requires 'MooseX::Declare' => '0.32';
 requires 'MooseX::Types::DateTime';
 requires 'MooseX::Types::ISO8601';
@@ -74,31 +82,31 @@ requires 'MooseX::Types::Common';
 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';
@@ -114,6 +122,16 @@ if ($Module::Install::AUTHOR) {
         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;
 
diff --git a/README b/README
index 86853b2..2de1bfa 100644 (file)
--- a/README
+++ b/README
@@ -41,7 +41,7 @@ GETTING GITALIST
 
     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.
@@ -73,7 +73,7 @@ INITIAL CONFIGURATION
 
       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
@@ -83,15 +83,15 @@ INITIAL CONFIGURATION
 
     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
index 98b3160..d2e747c 100644 (file)
@@ -1,10 +1,10 @@
 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"
 
index bd77889..2729895 100644 (file)
@@ -1,8 +1,8 @@
-<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>
 
index c59a836..3d2703a 100644 (file)
@@ -11,33 +11,49 @@ use Catalyst qw/
                 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__
@@ -90,7 +106,7 @@ Alternatively, you can get Gitalist using git.
 
 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.
@@ -123,21 +139,21 @@ by running:
 
   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
 
diff --git a/lib/Gitalist/ActionRole/FilenameArgs.pm b/lib/Gitalist/ActionRole/FilenameArgs.pm
new file mode 100644 (file)
index 0000000..f0ed177
--- /dev/null
@@ -0,0 +1,14 @@
+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;
+
diff --git a/lib/Gitalist/ContentMangler/Resolver.pm b/lib/Gitalist/ContentMangler/Resolver.pm
new file mode 100644 (file)
index 0000000..f0ba985
--- /dev/null
@@ -0,0 +1,6 @@
+package Gitalist::ContentMangler::Resolver;
+use Moose::Role;
+
+requires 'resolve';
+
+1;
diff --git a/lib/Gitalist/ContentMangler/Resolver/Default.pm b/lib/Gitalist/ContentMangler/Resolver/Default.pm
new file mode 100644 (file)
index 0000000..607f4d4
--- /dev/null
@@ -0,0 +1,9 @@
+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
diff --git a/lib/Gitalist/Controller.pm b/lib/Gitalist/Controller.pm
new file mode 100644 (file)
index 0000000..9839ac3
--- /dev/null
@@ -0,0 +1,7 @@
+package Gitalist::Controller;
+use Moose;
+use namespace::autoclean;
+
+BEGIN { extends 'Catalyst::Controller::ActionRole' }
+
+__PACKAGE__->meta->make_immutable;
diff --git a/lib/Gitalist/Controller/Fragment.pm b/lib/Gitalist/Controller/Fragment.pm
new file mode 100644 (file)
index 0000000..5a4bfd2
--- /dev/null
@@ -0,0 +1,32 @@
+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;
diff --git a/lib/Gitalist/Controller/Fragment/Ref.pm b/lib/Gitalist/Controller/Fragment/Ref.pm
new file mode 100644 (file)
index 0000000..a2e02e3
--- /dev/null
@@ -0,0 +1,143 @@
+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;
diff --git a/lib/Gitalist/Controller/Fragment/Repository.pm b/lib/Gitalist/Controller/Fragment/Repository.pm
new file mode 100644 (file)
index 0000000..b73c1a5
--- /dev/null
@@ -0,0 +1,33 @@
+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;
diff --git a/lib/Gitalist/Controller/LegacyURI.pm b/lib/Gitalist/Controller/LegacyURI.pm
new file mode 100644 (file)
index 0000000..a4c4420
--- /dev/null
@@ -0,0 +1,146 @@
+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;
diff --git a/lib/Gitalist/Controller/OPML.pm b/lib/Gitalist/Controller/OPML.pm
new file mode 100644 (file)
index 0000000..ece56f3
--- /dev/null
@@ -0,0 +1,29 @@
+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;
diff --git a/lib/Gitalist/Controller/Ref.pm b/lib/Gitalist/Controller/Ref.pm
new file mode 100644 (file)
index 0000000..207d4ca
--- /dev/null
@@ -0,0 +1,86 @@
+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;
diff --git a/lib/Gitalist/Controller/Repository.pm b/lib/Gitalist/Controller/Repository.pm
new file mode 100644 (file)
index 0000000..0aba16c
--- /dev/null
@@ -0,0 +1,131 @@
+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;
index be29129..a46fff0 100644 (file)
@@ -2,643 +2,37 @@ package Gitalist::Controller::Root;
 
 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!
@@ -649,12 +43,19 @@ sub base : Chained('/root') PathPart('') CaptureArgs(0) {
     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;
+    },
   );
 }
 
@@ -713,18 +114,8 @@ Provides the repository listing.
 
 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.
index ef36f05..0445999 100644 (file)
@@ -49,7 +49,7 @@ class Gitalist::Git::Object::Commit
 
         method diff ( Maybe[Bool] :$patch?,
                        Maybe[NonEmptySimpleStr] :$parent?,
-                       Maybe[NonEmptySimpleStr] :$file?
+                       Maybe[NonEmptySimpleStr] :$filename?
                    ) {
             $parent = $parent
                 ? $parent
@@ -57,7 +57,7 @@ class Gitalist::Git::Object::Commit
                         ? $self->parent_sha1
                             : '-c';
             my @etc = (
-                ( $file  ? ('--', $file) : () ),
+                ( $filename  ? ('--', $filename) : () ),
             );
 
             my @out = $self->_raw_diff(
@@ -105,7 +105,7 @@ class Gitalist::Git::Object::Commit
                 $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;
             }
@@ -128,7 +128,7 @@ class Gitalist::Git::Object::Commit
                     next;
                 }
 
-                if (/^index (\w+)\.\.(\w+) (\d+)$/) {
+                if (/^index (\w+)\.\.(\w+)(?: (\d+))?$/) {
                     @{$ret[-1]}{qw(index src dst mode)} = ($_, $1, $2, $3);
                     next
                 }
index a230129..e4eb595 100644 (file)
@@ -4,6 +4,7 @@ class Gitalist::Git::Repository with Gitalist::Git::HasUtils {
     # 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/;
@@ -78,6 +79,15 @@ class Gitalist::Git::Repository with Gitalist::Git::HasUtils {
     }
 
     ## 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;
@@ -129,7 +139,7 @@ class Gitalist::Git::Repository with Gitalist::Git::HasUtils {
             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 = (
@@ -180,11 +190,11 @@ class Gitalist::Git::Repository with Gitalist::Git::HasUtils {
     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) {
@@ -241,6 +251,8 @@ class Gitalist::Git::Repository with Gitalist::Git::HasUtils {
             $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;
     }
 
similarity index 98%
rename from lib/Gitalist/Model/GitRepos.pm
rename to lib/Gitalist/Model/CollectionOfRepos.pm
index deff310..2820b53 100644 (file)
@@ -1,4 +1,4 @@
-package Gitalist::Model::GitRepos;
+package Gitalist::Model::CollectionOfRepos;
 
 use Moose;
 use Gitalist::Git::CollectionOfRepositories::FromDirectory;
diff --git a/lib/Gitalist/Model/ContentMangler.pm b/lib/Gitalist/Model/ContentMangler.pm
new file mode 100644 (file)
index 0000000..62a3356
--- /dev/null
@@ -0,0 +1,61 @@
+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;
diff --git a/lib/Gitalist/URIStructure/Fragment/WithLog.pm b/lib/Gitalist/URIStructure/Fragment/WithLog.pm
new file mode 100644 (file)
index 0000000..ea3ae2a
--- /dev/null
@@ -0,0 +1,27 @@
+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;
diff --git a/lib/Gitalist/URIStructure/Ref.pm b/lib/Gitalist/URIStructure/Ref.pm
new file mode 100644 (file)
index 0000000..da71487
--- /dev/null
@@ -0,0 +1,85 @@
+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;
diff --git a/lib/Gitalist/URIStructure/Repository.pm b/lib/Gitalist/URIStructure/Repository.pm
new file mode 100644 (file)
index 0000000..976917e
--- /dev/null
@@ -0,0 +1,51 @@
+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;
diff --git a/lib/Gitalist/URIStructure/WithLog.pm b/lib/Gitalist/URIStructure/WithLog.pm
new file mode 100644 (file)
index 0000000..318522d
--- /dev/null
@@ -0,0 +1,11 @@
+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
index 0df4973..f11dc34 100644 (file)
@@ -45,6 +45,11 @@ sub age_string {
   return $age_str;
 }
 
+sub is_binary {
+  # Crappy heuristic - does the first line or so look printable?
+  return $_[0] !~ /^[[:print:]]+$ (?: \s ^[[:print:]]+$ )?/mx;
+}
+
 1;
 
 __END__
@@ -57,7 +62,11 @@ Gitalist::Utils - trivial utils for Gitalist
 
 =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
 
index 757f982..0c8d576 100644 (file)
@@ -1,16 +1,28 @@
 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__
index 2df82ed..9c28341 100644 (file)
@@ -9,37 +9,16 @@ use Syntax::Highlight::Engine::Kate::Perl ();
 
 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) {
diff --git a/root/_chroma_hash.tt2 b/root/_chroma_hash.tt2
deleted file mode 100644 (file)
index d7a0bb7..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-[%- 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>
old mode 100644 (file)
new mode 100755 (executable)
index b3062eb..11b4199
@@ -1,14 +1,33 @@
 [% 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
old mode 100644 (file)
new mode 100755 (executable)
index 2057772..7126a75
@@ -1,23 +1,18 @@
+<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'>
     [%
@@ -32,9 +27,9 @@
     %]
    </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 %]
index 2183ab5..1fbcfaa 100644 (file)
@@ -3,13 +3,13 @@
   <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 %]
diff --git a/root/_heads.tt2 b/root/_heads.tt2
deleted file mode 100644 (file)
index 0eb77e7..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-<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>
diff --git a/root/_history.tt2 b/root/_history.tt2
deleted file mode 100644 (file)
index 83f09e1..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-<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>
index c332d35..e98f0ee 100644 (file)
@@ -1,9 +1,9 @@
 <div class='pager'>
- <a href='[% c.uri_for(action, {h=HEAD}) %]'>HEAD</a> &sect;
+ <a href='[% c.uri_for_action('/' _ c.action, [Repository.name, 'HEAD']) %]'>HEAD</a> &sect;
  [% IF log_lines.first.sha1 != commit.sha1 %]
- <a href='[% c.request.uri_with(pg => page - 1) %]'>&laquo; prev</a>
+ <a href='[% c.request.uri_with(pg => (page||0) - 1) %]'>&laquo; prev</a>
  [% END %]
  [% IF log_lines.size == 50 %]
- <a href='[% c.request.uri_with(pg => page + 1) %]'>next &raquo;</a>
+ <a href='[% c.request.uri_with(pg => (page||0) + 1) %]'>next &raquo;</a>
  [% END %]
 </div>
index 71bb0ed..76625af 100644 (file)
@@ -1,7 +1,7 @@
 <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>
diff --git a/root/_shortlog.tt2 b/root/_shortlog.tt2
deleted file mode 100644 (file)
index 19caaf1..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-<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>
diff --git a/root/_tree.tt2 b/root/_tree.tt2
deleted file mode 100644 (file)
index 6a96cda..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-<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>
diff --git a/root/blame.tt2 b/root/blame.tt2
deleted file mode 100644 (file)
index 19d3e61..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-[% 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>
diff --git a/root/blob.tt2 b/root/blob.tt2
deleted file mode 100644 (file)
index 06077b2..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-[% 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>
diff --git a/root/blobdiff.tt2 b/root/blobdiff.tt2
deleted file mode 100644 (file)
index b771f74..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-[% PROCESS 'nav/actions.tt2' object = commit %]
-
-<div class='content'>
-  <div class='commit-message'>
-  [% short_cmt(commit.comment) | html %] ...
-  </div>
-
-  [% INCLUDE '_diff.tt2' %]
-</div>
diff --git a/root/blobdiff_plain.tt2 b/root/blobdiff_plain.tt2
deleted file mode 100644 (file)
index 4b771f4..0000000
+++ /dev/null
@@ -1 +0,0 @@
-[%- INCLUDE '_diff_plain.tt2' -%]
diff --git a/root/commit.tt2 b/root/commit.tt2
deleted file mode 100644 (file)
index 408eedc..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-[% 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 %] &lt;[% commit.author.email %]&gt;<br/>
-       [% commit.authored_time %]</dd>
-   <dt>committer</dt>
-    <dd>[% commit.committer.name %] &lt;[% commit.committer.email %]&gt;<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>
diff --git a/root/commitdiff.tt2 b/root/commitdiff.tt2
deleted file mode 100644 (file)
index 9db50ec..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-[% 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>
diff --git a/root/commitdiff_plain.tt2 b/root/commitdiff_plain.tt2
deleted file mode 100644 (file)
index 4b771f4..0000000
+++ /dev/null
@@ -1 +0,0 @@
-[%- INCLUDE '_diff_plain.tt2' -%]
diff --git a/root/default.tt2 b/root/default.tt2
deleted file mode 100644 (file)
index d38cdcb..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-[%- 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 -%]
old mode 100644 (file)
new mode 100755 (executable)
index 5ad723d..fea2fec
Binary files a/root/favicon.ico and b/root/favicon.ico differ
diff --git a/root/favicon.png b/root/favicon.png
deleted file mode 100644 (file)
index de637c0..0000000
Binary files a/root/favicon.png and /dev/null differ
diff --git a/root/fragment/collectionofrepositories.tt2 b/root/fragment/collectionofrepositories.tt2
new file mode 100755 (executable)
index 0000000..2b153d3
--- /dev/null
@@ -0,0 +1,17 @@
+<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>
diff --git a/root/fragment/ref/blame.tt2 b/root/fragment/ref/blame.tt2
new file mode 100755 (executable)
index 0000000..af465d4
--- /dev/null
@@ -0,0 +1,21 @@
+[% 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 %]
diff --git a/root/fragment/ref/blob.tt2 b/root/fragment/ref/blob.tt2
new file mode 100644 (file)
index 0000000..3fe51e8
--- /dev/null
@@ -0,0 +1,8 @@
+[%- 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 -%]
diff --git a/root/fragment/ref/commit.tt2 b/root/fragment/ref/commit.tt2
new file mode 100755 (executable)
index 0000000..8560e1f
--- /dev/null
@@ -0,0 +1,67 @@
+<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;
+  %]
diff --git a/root/fragment/ref/diff_fancy.tt2 b/root/fragment/ref/diff_fancy.tt2
new file mode 100755 (executable)
index 0000000..7cba200
--- /dev/null
@@ -0,0 +1,20 @@
+[%
+  # 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 %]
+
diff --git a/root/fragment/ref/diff_plain.tt2 b/root/fragment/ref/diff_plain.tt2
new file mode 100644 (file)
index 0000000..0f58361
--- /dev/null
@@ -0,0 +1,5 @@
+[%- FOREACH item IN diff -%]
+diff --git [% item.a _ ' ' _ item.b %]
+[% item.index %]
+[% blobs.${loop.index} %]
+[%- END -%]
diff --git a/root/fragment/ref/history.tt2 b/root/fragment/ref/history.tt2
new file mode 100755 (executable)
index 0000000..e20dda7
--- /dev/null
@@ -0,0 +1,53 @@
+[% 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' %]
diff --git a/root/fragment/ref/longlog.tt2 b/root/fragment/ref/longlog.tt2
new file mode 100644 (file)
index 0000000..5470847
--- /dev/null
@@ -0,0 +1 @@
+[% PROCESS 'fragment/repository/longlog.tt2' %]
diff --git a/root/fragment/ref/shortlog.tt2 b/root/fragment/ref/shortlog.tt2
new file mode 100644 (file)
index 0000000..0ba3aa1
--- /dev/null
@@ -0,0 +1 @@
+[% PROCESS 'fragment/repository/shortlog.tt2' %]
diff --git a/root/fragment/ref/tree.tt2 b/root/fragment/ref/tree.tt2
new file mode 100755 (executable)
index 0000000..0ec6c16
--- /dev/null
@@ -0,0 +1,60 @@
+[% 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
diff --git a/root/fragment/repository/heads.tt2 b/root/fragment/repository/heads.tt2
new file mode 100755 (executable)
index 0000000..69c5766
--- /dev/null
@@ -0,0 +1,27 @@
+[% 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>
diff --git a/root/fragment/repository/longlog.tt2 b/root/fragment/repository/longlog.tt2
new file mode 100755 (executable)
index 0000000..3f11484
--- /dev/null
@@ -0,0 +1,5 @@
+[% INCLUDE 'fragment/repository/shortlog.tt2' longlogformat = 1 %]
+
+
+<h2>Branches</h2>
+[% subinclude('/fragment/repository/heads', [Repository.name]) %]
diff --git a/root/fragment/repository/shortlog.tt2 b/root/fragment/repository/shortlog.tt2
new file mode 100755 (executable)
index 0000000..0cde010
--- /dev/null
@@ -0,0 +1,49 @@
+[% 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' %]
diff --git a/root/fragment/repository/summary.tt2 b/root/fragment/repository/summary.tt2
new file mode 100755 (executable)
index 0000000..a2a160c
--- /dev/null
@@ -0,0 +1,5 @@
+<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>
diff --git a/root/fragment/repository/tags.tt2 b/root/fragment/repository/tags.tt2
new file mode 100644 (file)
index 0000000..3f47409
--- /dev/null
@@ -0,0 +1 @@
+[% INCLUDE 'fragment/repository/heads.tt2' heads = tags %]
diff --git a/root/git-logo.png b/root/git-logo.png
deleted file mode 100644 (file)
index 16ae8d5..0000000
Binary files a/root/git-logo.png and /dev/null differ
diff --git a/root/gitweb.css b/root/gitweb.css
deleted file mode 100644 (file)
index e5473aa..0000000
+++ /dev/null
@@ -1,501 +0,0 @@
-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;
-}
diff --git a/root/gitweb.tt2 b/root/gitweb.tt2
deleted file mode 100644 (file)
index dd1a5ed..0000000
+++ /dev/null
@@ -1 +0,0 @@
-[% gitweb_output %]
diff --git a/root/heads.tt2 b/root/heads.tt2
deleted file mode 100644 (file)
index baa8e4b..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-[% INCLUDE 'nav/actions.tt2' object = commit %]
-
-<div class='content'>
-  <div>
-  [% Repository.name %]
-  </div>
-
-  [% INCLUDE '_heads.tt2' %]
-</div>
diff --git a/root/history.tt2 b/root/history.tt2
deleted file mode 100644 (file)
index babb960..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-[% INCLUDE 'nav/actions.tt2' object = commit %]
-
-[%
-  INCLUDE '_log_pager.tt2';
-  INCLUDE '_history.tt2';
-  INCLUDE '_log_pager.tt2';
-%]
diff --git a/root/inc/chroma_hash.tt2 b/root/inc/chroma_hash.tt2
new file mode 100755 (executable)
index 0000000..b07a1ea
--- /dev/null
@@ -0,0 +1,13 @@
+[%- 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 %]
similarity index 74%
rename from root/_footer_feeds.tt2
rename to root/inc/footer_feeds.tt2
index 3e99e51..2d598f9 100644 (file)
     <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 %]
diff --git a/root/inc/log_pager.tt2 b/root/inc/log_pager.tt2
new file mode 100755 (executable)
index 0000000..e58aaab
--- /dev/null
@@ -0,0 +1,11 @@
+<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>
index 5fc9dad..56700a7 100644 (file)
@@ -1 +1 @@
-[%- 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 -%]
old mode 100644 (file)
new mode 100755 (executable)
index 9d1544d..5df3c17
@@ -1,45 +1,20 @@
-<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>
diff --git a/root/log.tt2 b/root/log.tt2
deleted file mode 100644 (file)
index 3e3908a..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-[% 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>
diff --git a/root/logo.svg b/root/logo.svg
deleted file mode 100644 (file)
index f0367df..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-<?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>
index 52ca63e..7845ca9 100644 (file)
@@ -1,20 +1,26 @@
+[%- 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> &bull;
-    <a href="[% c.uri_for('shortlog', {h=object.sha1}) %]">shortlog</a> &bull;
-    <a href="[% c.uri_for('log', {h=object.sha1}) %]">log</a> &bull;
-    <a href="[% c.uri_for('commit', {h=object.sha1}) %]">commit</a> &bull;
-    <a href="[% c.uri_for('commitdiff', {h=object.sha1}) %]">commitdiff</a>
-    [% IF object.type == 'commit' %] &bull;
-    <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> &bull;
+    [% 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> &bull;
+    <a href="[% c.uri_for_action('/' _ path _ '/longlog', c.req.captures) %]">log</a>
+    [% IF Commit %]
+        &sect;
+        <a href="[% c.uri_for_action('/ref/commit', [c.req.captures.0, Commit.sha1]) %]">commit</a> &bull;
+        <a href="[% c.uri_for_action('/ref/diff_fancy', [c.req.captures.0, Commit.sha1]) %]">commitdiff</a> &bull;
+        <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' %]
     &sect;
-    <a href="[% c.uri_for('blob', {h=object.sha1,f=filename}) %]">blob</a> &bull;
-    <a href="[% c.uri_for('blob_plain', {h=object.sha1,f=filename}) %]">raw</a> &bull;
-    <a href="[% c.uri_for('blame', {h=object.sha1,f=filename}) %]">blame</a> &bull;
-    <a href="[% c.uri_for('shortlog', {h=object.sha1,f=filename}) %]">history</a> &bull;
-    <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> &bull;
+    <a href="[% c.uri_for_action('/ref/raw', [c.req.captures.0, Commit.sha1], filename) %]">raw</a> &bull;
+    <a href="[% c.uri_for_action('/ref/blame', [c.req.captures.0, Commit.sha1], filename)  %]">blame</a> &bull;
+    <a href="[% c.uri_for_action('/ref/history', [c.req.captures.0, Commit.sha1], filename)  %]">history</a> &bull;
+    <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>
old mode 100644 (file)
new mode 100755 (executable)
index eef339c..3567c09
@@ -1,7 +1,6 @@
-<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>
+
old mode 100644 (file)
new mode 100755 (executable)
index 35c3d88..9721094
@@ -1,9 +1,9 @@
+[% 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 %]
diff --git a/root/opml.tt2 b/root/opml.tt2
new file mode 100644 (file)
index 0000000..35f22e3
--- /dev/null
@@ -0,0 +1,19 @@
+<?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>
diff --git a/root/ref/blame.tt2 b/root/ref/blame.tt2
new file mode 100755 (executable)
index 0000000..f943636
--- /dev/null
@@ -0,0 +1,37 @@
+[%- 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 %]
+
diff --git a/root/ref/blob.tt2 b/root/ref/blob.tt2
new file mode 100755 (executable)
index 0000000..92fbf03
--- /dev/null
@@ -0,0 +1,12 @@
+<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
diff --git a/root/ref/commit.tt2 b/root/ref/commit.tt2
new file mode 100644 (file)
index 0000000..2d79fa7
--- /dev/null
@@ -0,0 +1,4 @@
+
+<div class='content'>
+  [% subinclude('/fragment/ref/commit', c.req.captures) %]
+</div>
diff --git a/root/ref/diff_fancy.tt2 b/root/ref/diff_fancy.tt2
new file mode 100755 (executable)
index 0000000..312c097
--- /dev/null
@@ -0,0 +1,25 @@
+
+<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)
+  %]
diff --git a/root/ref/diff_plain.tt2 b/root/ref/diff_plain.tt2
new file mode 100644 (file)
index 0000000..0f98a04
--- /dev/null
@@ -0,0 +1,2 @@
+[% subinclude('/fragment/' _ c.action, c.req.captures, c.req.args.0 c.req.args.1) %]
+
diff --git a/root/ref/history.tt2 b/root/ref/history.tt2
new file mode 100644 (file)
index 0000000..5820d4d
--- /dev/null
@@ -0,0 +1,2 @@
+[%# 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) %]
diff --git a/root/ref/longlog.tt2 b/root/ref/longlog.tt2
new file mode 100644 (file)
index 0000000..e927a16
--- /dev/null
@@ -0,0 +1 @@
+[% PROCESS 'repository/longlog.tt2' %]
diff --git a/root/ref/shortlog.tt2 b/root/ref/shortlog.tt2
new file mode 100644 (file)
index 0000000..4175b41
--- /dev/null
@@ -0,0 +1 @@
+[% PROCESS 'repository/shortlog.tt2' %]
diff --git a/root/ref/tree.tt2 b/root/ref/tree.tt2
new file mode 100755 (executable)
index 0000000..6d76c32
--- /dev/null
@@ -0,0 +1 @@
+[% subinclude('/fragment/ref/tree', c.req.captures, c.req.args.to_path) %]
diff --git a/root/repository/atom.tt2 b/root/repository/atom.tt2
new file mode 100644 (file)
index 0000000..9f721ab
--- /dev/null
@@ -0,0 +1,15 @@
+<?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>
diff --git a/root/repository/heads.tt2 b/root/repository/heads.tt2
new file mode 100644 (file)
index 0000000..1d8d910
--- /dev/null
@@ -0,0 +1 @@
+[% subinclude('/fragment/repository/heads', c.req.captures) %]
diff --git a/root/repository/longlog.tt2 b/root/repository/longlog.tt2
new file mode 100644 (file)
index 0000000..a0c9f4b
--- /dev/null
@@ -0,0 +1 @@
+[% subinclude('/fragment/' _ c.action, c.req.captures, c.req.parameters) %]
similarity index 100%
rename from root/reflog.tt2
rename to root/repository/reflog.tt2
diff --git a/root/repository/rss.tt2 b/root/repository/rss.tt2
new file mode 100644 (file)
index 0000000..bd2c766
--- /dev/null
@@ -0,0 +1,19 @@
+<?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>
diff --git a/root/repository/search.tt2 b/root/repository/search.tt2
new file mode 100755 (executable)
index 0000000..901d4d6
--- /dev/null
@@ -0,0 +1,35 @@
+[% 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
diff --git a/root/repository/shortlog.tt2 b/root/repository/shortlog.tt2
new file mode 100755 (executable)
index 0000000..90f7ea4
--- /dev/null
@@ -0,0 +1,2 @@
+[% subinclude('/fragment/' _ c.action, c.req.captures, c.req.parameters) %]
+
diff --git a/root/repository/summary.tt2 b/root/repository/summary.tt2
new file mode 100755 (executable)
index 0000000..a0646e8
--- /dev/null
@@ -0,0 +1,15 @@
+
+
+  <!-- [% 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 %]
+
diff --git a/root/repository/tags.tt2 b/root/repository/tags.tt2
new file mode 100755 (executable)
index 0000000..3518081
--- /dev/null
@@ -0,0 +1,7 @@
+<div class='content'>
+  <div>
+  [% Repository.name %]
+  </div>
+
+  [% subinclude('/fragment/repository/tags', c.req.captures) %]
+</div>
old mode 100644 (file)
new mode 100755 (executable)
index 2504b82..06d845c
@@ -1,35 +1 @@
-[% 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
old mode 100644 (file)
new mode 100755 (executable)
index c23a414..86e8154
@@ -1,10 +1,12 @@
-[% 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>
@@ -25,4 +27,4 @@ added, removed or "modified" the string) will be listed. This search can take a
 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>
diff --git a/root/shortlog.tt2 b/root/shortlog.tt2
deleted file mode 100644 (file)
index 6f9636e..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-[% INCLUDE 'nav/actions.tt2' object = commit %]
-
-<div class='content'>
-[%
-  INCLUDE '_log_pager.tt2';
-  INCLUDE '_shortlog.tt2';
-  INCLUDE '_log_pager.tt2';
-%]
-</div>
diff --git a/root/static/css/blueprint/ie.css b/root/static/css/blueprint/ie.css
deleted file mode 100644 (file)
index f336f0e..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/* -----------------------------------------------------------------------
-
-
- 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
diff --git a/root/static/css/blueprint/print.css b/root/static/css/blueprint/print.css
deleted file mode 100644 (file)
index fdb8220..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/* -----------------------------------------------------------------------
-
-
- 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
diff --git a/root/static/css/blueprint/screen.css b/root/static/css/blueprint/screen.css
deleted file mode 100644 (file)
index 8d05e3c..0000000
+++ /dev/null
@@ -1,254 +0,0 @@
-/* -----------------------------------------------------------------------
-
-
- 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;}
diff --git a/root/static/css/core.css b/root/static/css/core.css
new file mode 100755 (executable)
index 0000000..09c3c7a
--- /dev/null
@@ -0,0 +1,540 @@
+#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;
+}
diff --git a/root/static/css/site.css b/root/static/css/site.css
deleted file mode 100644 (file)
index a968bc5..0000000
+++ /dev/null
@@ -1,306 +0,0 @@
-#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;
-}
old mode 100644 (file)
new mode 100755 (executable)
index a76b6fb..0303541
@@ -1,16 +1,21 @@
 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;
 }
diff --git a/root/static/favicon.ico b/root/static/favicon.ico
new file mode 100755 (executable)
index 0000000..fea2fec
Binary files /dev/null and b/root/static/favicon.ico differ
diff --git a/root/static/i/arrow_down_white.gif b/root/static/i/arrow_down_white.gif
new file mode 100755 (executable)
index 0000000..a8ef359
Binary files /dev/null and b/root/static/i/arrow_down_white.gif differ
diff --git a/root/static/i/arrow_grey.gif b/root/static/i/arrow_grey.gif
new file mode 100755 (executable)
index 0000000..3a4429e
Binary files /dev/null and b/root/static/i/arrow_grey.gif differ
diff --git a/root/static/i/arrow_grey_left.gif b/root/static/i/arrow_grey_left.gif
new file mode 100755 (executable)
index 0000000..42e070a
Binary files /dev/null and b/root/static/i/arrow_grey_left.gif differ
diff --git a/root/static/i/bg.png b/root/static/i/bg.png
new file mode 100755 (executable)
index 0000000..1c48ca4
Binary files /dev/null and b/root/static/i/bg.png differ
diff --git a/root/static/i/bg_bottom.png b/root/static/i/bg_bottom.png
new file mode 100755 (executable)
index 0000000..cda2f73
Binary files /dev/null and b/root/static/i/bg_bottom.png differ
diff --git a/root/static/i/bg_content.png b/root/static/i/bg_content.png
new file mode 100755 (executable)
index 0000000..c6dc6b5
Binary files /dev/null and b/root/static/i/bg_content.png differ
diff --git a/root/static/i/bg_top.png b/root/static/i/bg_top.png
new file mode 100755 (executable)
index 0000000..65601c4
Binary files /dev/null and b/root/static/i/bg_top.png differ
diff --git a/root/static/i/buttons/search.png b/root/static/i/buttons/search.png
new file mode 100755 (executable)
index 0000000..4768621
Binary files /dev/null and b/root/static/i/buttons/search.png differ
diff --git a/root/static/i/favicon.gif b/root/static/i/favicon.gif
new file mode 100755 (executable)
index 0000000..29319a5
Binary files /dev/null and b/root/static/i/favicon.gif differ
diff --git a/root/static/i/favicon.png b/root/static/i/favicon.png
new file mode 100755 (executable)
index 0000000..9c14c24
Binary files /dev/null and b/root/static/i/favicon.png differ
diff --git a/root/static/i/icons/Thumbs.db b/root/static/i/icons/Thumbs.db
new file mode 100644 (file)
index 0000000..c804544
Binary files /dev/null and b/root/static/i/icons/Thumbs.db differ
diff --git a/root/static/i/icons/attention.png b/root/static/i/icons/attention.png
new file mode 100755 (executable)
index 0000000..db00074
Binary files /dev/null and b/root/static/i/icons/attention.png differ
diff --git a/root/static/i/icons/blame.png b/root/static/i/icons/blame.png
new file mode 100755 (executable)
index 0000000..7a6730b
Binary files /dev/null and b/root/static/i/icons/blame.png differ
diff --git a/root/static/i/icons/blob.png b/root/static/i/icons/blob.png
new file mode 100755 (executable)
index 0000000..c5261b8
Binary files /dev/null and b/root/static/i/icons/blob.png differ
diff --git a/root/static/i/icons/button_sha1.png b/root/static/i/icons/button_sha1.png
new file mode 100755 (executable)
index 0000000..77915e0
Binary files /dev/null and b/root/static/i/icons/button_sha1.png differ
diff --git a/root/static/i/icons/button_sha1_invert.png b/root/static/i/icons/button_sha1_invert.png
new file mode 100755 (executable)
index 0000000..2f1724b
Binary files /dev/null and b/root/static/i/icons/button_sha1_invert.png differ
diff --git a/root/static/i/icons/commit.png b/root/static/i/icons/commit.png
new file mode 100755 (executable)
index 0000000..692f11e
Binary files /dev/null and b/root/static/i/icons/commit.png differ
diff --git a/root/static/i/icons/diff.png b/root/static/i/icons/diff.png
new file mode 100755 (executable)
index 0000000..9883936
Binary files /dev/null and b/root/static/i/icons/diff.png differ
diff --git a/root/static/i/icons/diffcurrent.png b/root/static/i/icons/diffcurrent.png
new file mode 100755 (executable)
index 0000000..8f4827f
Binary files /dev/null and b/root/static/i/icons/diffcurrent.png differ
diff --git a/root/static/i/icons/file.png b/root/static/i/icons/file.png
new file mode 100755 (executable)
index 0000000..1d0e6e0
Binary files /dev/null and b/root/static/i/icons/file.png differ
diff --git a/root/static/i/icons/folder.png b/root/static/i/icons/folder.png
new file mode 100755 (executable)
index 0000000..2016319
Binary files /dev/null and b/root/static/i/icons/folder.png differ
diff --git a/root/static/i/icons/fulllog.gif b/root/static/i/icons/fulllog.gif
new file mode 100755 (executable)
index 0000000..536da14
Binary files /dev/null and b/root/static/i/icons/fulllog.gif differ
diff --git a/root/static/i/icons/history.png b/root/static/i/icons/history.png
new file mode 100755 (executable)
index 0000000..690a489
Binary files /dev/null and b/root/static/i/icons/history.png differ
diff --git a/root/static/i/icons/longlog.png b/root/static/i/icons/longlog.png
new file mode 100755 (executable)
index 0000000..4859ac9
Binary files /dev/null and b/root/static/i/icons/longlog.png differ
diff --git a/root/static/i/icons/raw.png b/root/static/i/icons/raw.png
new file mode 100755 (executable)
index 0000000..f2854f6
Binary files /dev/null and b/root/static/i/icons/raw.png differ
diff --git a/root/static/i/icons/shortlog.gif b/root/static/i/icons/shortlog.gif
new file mode 100755 (executable)
index 0000000..0f1e9b0
Binary files /dev/null and b/root/static/i/icons/shortlog.gif differ
diff --git a/root/static/i/icons/shortlog.png b/root/static/i/icons/shortlog.png
new file mode 100755 (executable)
index 0000000..9c48a2a
Binary files /dev/null and b/root/static/i/icons/shortlog.png differ
diff --git a/root/static/i/icons/tree.gif b/root/static/i/icons/tree.gif
new file mode 100755 (executable)
index 0000000..49d75b8
Binary files /dev/null and b/root/static/i/icons/tree.gif differ
diff --git a/root/static/i/icons/tree.png b/root/static/i/icons/tree.png
new file mode 100755 (executable)
index 0000000..139a962
Binary files /dev/null and b/root/static/i/icons/tree.png differ
diff --git a/root/static/i/logo.png b/root/static/i/logo.png
new file mode 100755 (executable)
index 0000000..cb0e1f8
Binary files /dev/null and b/root/static/i/logo.png differ
diff --git a/root/static/js/site.js b/root/static/js/site.js
new file mode 100755 (executable)
index 0000000..3c748fe
--- /dev/null
@@ -0,0 +1,86 @@
+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);
+});
diff --git a/root/summary.tt2 b/root/summary.tt2
deleted file mode 100644 (file)
index be4b3e1..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-[% 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>
diff --git a/root/tags.tt2 b/root/tags.tt2
deleted file mode 100644 (file)
index 6f47285..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-[% INCLUDE 'nav/actions.tt2' object = commit %]
-<div class='content'>
-  <div>
-  [% Repository.name %]
-  </div>
-
-  [% INCLUDE '_heads.tt2' heads = tags %]
-</div>
diff --git a/root/tree.tt2 b/root/tree.tt2
deleted file mode 100644 (file)
index bc06ea5..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-[% 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>
diff --git a/root/wrapper.tt2 b/root/wrapper.tt2
new file mode 100755 (executable)
index 0000000..ad3bb5c
--- /dev/null
@@ -0,0 +1,198 @@
+[%- 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 -%]
diff --git a/script/bootstrap.pl b/script/bootstrap.pl
new file mode 100644 (file)
index 0000000..269f899
--- /dev/null
@@ -0,0 +1,81 @@
+#!/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";
+
diff --git a/script/env b/script/env
new file mode 100755 (executable)
index 0000000..7f96991
--- /dev/null
@@ -0,0 +1,79 @@
+#!/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;
+
index 9ef29e6..4afe54e 100755 (executable)
@@ -1,5 +1,8 @@
 #!/usr/bin/env perl
 
+use FindBin;
+BEGIN { do "$FindBin::Bin/env" or die $@ }
+
 use Catalyst::ScriptRunner;
 Catalyst::ScriptRunner->run('Gitalist', 'CGI');
 
index 41cf45e..b8e3fea 100755 (executable)
@@ -1,4 +1,6 @@
 #!/usr/bin/env perl
+use FindBin;
+BEGIN { do "$FindBin::Bin/env" or die $@ }
 
 use strict;
 use warnings;
index 37f989b..6948d49 100755 (executable)
@@ -1,4 +1,6 @@
 #!/usr/bin/env perl
+use FindBin;
+BEGIN { do "$FindBin::Bin/env" or die $@ }
 
 use Catalyst::ScriptRunner;
 Catalyst::ScriptRunner->run('Gitalist','FastCGI');
index 2e60bce..37d6b1f 100755 (executable)
@@ -1,4 +1,6 @@
 #!/usr/bin/env perl
+use FindBin;
+BEGIN { do "$FindBin::Bin/env" or die $@ }
 
 BEGIN {
     $ENV{CATALYST_SCRIPT_GEN} = 40;
index 67621d5..ab28c5c 100755 (executable)
@@ -1,4 +1,6 @@
 #!/usr/bin/env perl
+use FindBin;
+BEGIN { do "$FindBin::Bin/env" or die $@ }
 
 use Catalyst::ScriptRunner;
 Catalyst::ScriptRunner->run('Gitalist','Test');
index 2ed2537..f52f36e 100644 (file)
--- a/t/01app.t
+++ b/t/01app.t
@@ -1,63 +1,58 @@
 #!/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);
-    };
-};
index 3cdc2cc..bb49cf7 100644 (file)
@@ -59,7 +59,7 @@ my $commit_obj = Gitalist::Git::Object::Commit->new(
 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];
index 3017ef7..839d794 100644 (file)
@@ -1,22 +1,34 @@
 #!/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');
@@ -50,6 +62,7 @@ test('/', 'a=blob_plain;f=file1;hb=HEAD');
 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');
@@ -98,7 +111,6 @@ test('/', 'a=commitdiff_plain;h=master;hp=3f7567c7bdf7e7ebf410926493b92d39833311
 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');
@@ -202,7 +214,6 @@ test('/', 'a=tree;hb=HEAD');
 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');
@@ -233,10 +244,6 @@ test('/', 'a=rss;h=refs/heads/master');
 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');
@@ -248,19 +255,3 @@ test('/', 'a=blame;f=file1;hb=3bc0634310b9c62222bb0e724c11ffdfb297b4ac');
 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);
-    };
-};
diff --git a/t/app-mech-rootpage.t b/t/app-mech-rootpage.t
new file mode 100644 (file)
index 0000000..cc6f71f
--- /dev/null
@@ -0,0 +1,33 @@
+#!/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;
diff --git a/t/atom.t b/t/atom.t
new file mode 100644 (file)
index 0000000..13c835f
--- /dev/null
+++ b/t/atom.t
@@ -0,0 +1,18 @@
+#!/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;
index 6617816..e5661a1 100644 (file)
@@ -1,6 +1,6 @@
-<Model::GitRepos>
+<Model::CollectionOfRepos>
     repo_dir __path_to(t/lib/repositories)__
-</Model::GitRepos>
+</Model::CollectionOfRepos>
 
 name Gitalist
 
diff --git a/t/lib/TestGitalist.pm b/t/lib/TestGitalist.pm
new file mode 100644 (file)
index 0000000..dcdc539
--- /dev/null
@@ -0,0 +1,95 @@
+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;
diff --git a/t/lib/gitalist_testing.conf b/t/lib/gitalist_testing.conf
deleted file mode 100644 (file)
index 8e0aecf..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-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
diff --git a/t/lib/repositories/repo1/refs/tags/0.01 b/t/lib/repositories/repo1/refs/tags/0.01
new file mode 100644 (file)
index 0000000..7c4a265
--- /dev/null
@@ -0,0 +1 @@
+36c6c6708b8360d7023e8a1649c45bcf9b3bd818
similarity index 77%
rename from t/model_gitrepos.t
rename to t/model_collectionofrepos.t
index ee78cb6..e847c33 100644 (file)
@@ -12,9 +12,9 @@ use Class::MOP::Class;
 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 { {} });
@@ -48,10 +48,10 @@ our $ctx_gen = 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';
 
 {
@@ -64,25 +64,25 @@ throws_ok { Gitalist::Model::GitRepos->COMPONENT($ctx_gen->(), { repo_dir => '/d
 }
 
 # 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';
 }
 
 {
@@ -104,7 +104,7 @@ sub test_with_config {
     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';
diff --git a/t/opml.t b/t/opml.t
new file mode 100644 (file)
index 0000000..d468b44
--- /dev/null
+++ b/t/opml.t
@@ -0,0 +1,15 @@
+#!/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;
diff --git a/t/rss.t b/t/rss.t
new file mode 100644 (file)
index 0000000..2d6a143
--- /dev/null
+++ b/t/rss.t
@@ -0,0 +1,15 @@
+#!/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;
diff --git a/t/script/gitalist_server.pl b/t/script/gitalist_server.pl
new file mode 100755 (executable)
index 0000000..344bbeb
--- /dev/null
@@ -0,0 +1,14 @@
+#!/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;
+