Initial cut at /blame action.
Dan Brook [Fri, 20 Nov 2009 14:06:43 +0000 (14:06 +0000)]
lib/Gitalist/Controller/Root.pm
lib/Gitalist/Git/Object/Blob.pm
lib/Gitalist/Git/Object/Commit.pm
root/blame.tt2 [new file with mode: 0644]

index f4ab6db..d1c8cf4 100644 (file)
@@ -133,6 +133,28 @@ sub tags : Local {
   );
 }
 
+sub blame : Local {
+  my($self, $c) = @_;
+
+  my $project = $c->stash->{Project};
+  my $h  = $c->req->param('h')
+       || $project->hash_by_path($c->req->param('hb'), $c->req->param('f'))
+       || die "No file or sha1 provided.";
+  my $hb = $c->req->param('hb')
+       || $project->head_hash
+       || die "Couldn't discern the corresponding head.";
+  my $filename = $c->req->param('f') || '';
+
+  my($metadata, $filedata) = $project->get_object($hb)->blame($filename);
+  $c->stash(
+    metadata => $metadata,
+    filedata => $filedata,
+    head     => $project->get_object($hb),
+    filename => $filename,
+  );
+  
+}
+
 =head2 blob
 
 The blob action i.e the contents of a file.
@@ -568,10 +590,6 @@ sub opml : Local {
     # FIXME - implement snapshot
     Carp::croak "Not implemented.";
 }
-sub blame : Local {
-    # FIXME - implement snapshot
-    Carp::croak "Not implemented.";
-}
 
 =head2 end
 
index 4629c0b..51be7e3 100644 (file)
@@ -2,5 +2,7 @@ package Gitalist::Git::Object::Blob;
 use MooseX::Declare;
 
 class Gitalist::Git::Object::Blob extends Gitalist::Git::Object {
-        has '+type' => ( default => 'blob' );
+  use MooseX::Types::Common::String qw/NonEmptySimpleStr/;
+
+  has '+type' => ( default => 'blob' );
 }
index 5a125f6..68b2469 100644 (file)
@@ -140,4 +140,37 @@ class Gitalist::Git::Object::Commit
             return @ret;
         }
 
+
+  method blame ( NonEmptySimpleStr $filename ) {
+    my @blameout = $self->_run_cmd_list(
+      blame => '-p', $self->sha1, '--', $filename
+    );
+
+    my(%metadata, @filedata);
+    while(defined(local $_ = shift @blameout)) {
+      my ($sha1, $orig_lineno, $lineno, $group_size) =
+       /^([0-9a-f]{40}) (\d+) (\d+)(?: (\d+))?$/;
+
+      my $meta = $metadata{$sha1} ||= {
+       orig_lineno => $orig_lineno,
+       lineno => $lineno,
+       group_size => $group_size,
+      };
+
+      my $line;
+      while(defined($line = shift @blameout)) {
+       last
+         if $line =~ s/^\t//;
+       $meta->{$1} = $2
+         if $line =~ /^(\S+) (.*)/;
+      }
+
+      $meta->{parent} = $self->_run_cmd('rev-parse', "$sha1^")
+        unless exists $meta->{parent};
+
+      push @filedata, { line => $line, sha1 => $sha1 };
     }
+
+    return \%metadata, \@filedata;
+  }
+}
diff --git a/root/blame.tt2 b/root/blame.tt2
new file mode 100644 (file)
index 0000000..9c3958f
--- /dev/null
@@ -0,0 +1,16 @@
+[% PROCESS 'nav/actions.tt2' object = head %]
+[% IF object.type == 'commit' %]
+<div class='commit-message'>
+[% head.comment.substr(0, 85) %] ...
+</div>
+[% END %]
+
+<h3>BLOB PATH</h3>
+
+<div class='blame'>
+<table>
+[% FOR info IN filedata %]
+<tr><td>[% info.sha1 %]</td><td><pre>[% info.line | html %]</pre></td></tr>
+[% END %]
+</table>
+</div>