X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FGitalist%2FGit%2FObject%2FCommit.pm;h=1fd472c3274e4eda86096cfc661ef6b5eb429bd2;hb=09717a40ef5a5d43158701e91ead9ac7934880db;hp=68b2469a07ed158736e2a0b5105b44e138dd3126;hpb=18a8059ab308cfd22f3b1c4ce8cdb39afc55c8f6;p=catagits%2FGitalist.git diff --git a/lib/Gitalist/Git/Object/Commit.pm b/lib/Gitalist/Git/Object/Commit.pm index 68b2469..1fd472c 100644 --- a/lib/Gitalist/Git/Object/Commit.pm +++ b/lib/Gitalist/Git/Object/Commit.pm @@ -5,7 +5,7 @@ class Gitalist::Git::Object::Commit extends Gitalist::Git::Object with Gitalist::Git::Object::HasTree { use MooseX::Types::Moose qw/Str Int Bool Maybe ArrayRef/; - use MooseX::Types::Common::String qw/NonEmptySimpleStr/; + use MooseX::Types::Common::String qw/NonEmptySimpleStr SimpleStr/; use Moose::Autobox; use List::MoreUtils qw/any zip/; our $SHA1RE = qr/[0-9a-fA-F]{40}/; @@ -23,6 +23,23 @@ class Gitalist::Git::Object::Commit ], ); + method _build_tree { + return [$self->repository->get_object($self->tree_sha1)]; + } + + method sha_by_path ($path) { + $path =~ s{/+$}(); + # FIXME should this really just take the first result? + my @paths = $self->repository->run_cmd('ls-tree', $self->sha1, '--', $path) + or return; + my $line = $paths[0]; + + #'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa panic.c' + $line =~ m/^([0-9]+) (.+) ($SHA1RE)\t/; + my $sha1 = $3; + return $self->repository->get_object($sha1); + } + method get_patch ( Maybe[NonEmptySimpleStr] $parent_hash?, Int $patch_count?) { # assembling the git command to execute... @@ -47,23 +64,29 @@ class Gitalist::Git::Object::Commit return $self->_run_cmd_fh( @cmd ); } - method diff ( Maybe[Bool] :$patch?, - Maybe[NonEmptySimpleStr] :$parent?, - Maybe[NonEmptySimpleStr] :$file? - ) { + method diff ( Bool :$patch?, + NonEmptySimpleStr :$parent?, + NonEmptySimpleStr :$filename? + ) { $parent = $parent ? $parent : $self->parents <= 1 ? $self->parent_sha1 : '-c'; my @etc = ( - ( $file ? ('--', $file) : () ), + ( $filename ? ('--', $filename) : () ), ); + # If we're not comparing against something and we have multiple + # parents then it's a merge commit so show what was merged. + my $sha1 = $parent && $parent eq '-c' && @{[$self->parents]} > 1 + ? sprintf("%s^1..%s^2", ($self->sha1) x 2) + : $self->sha1; + my @out = $self->_raw_diff( ( $patch ? '--patch-with-raw' : () ), ( $parent ? $parent : () ), - $self->sha1, @etc, + $sha1, @etc, ); # XXX Yes, there is much wrongness having _parse_diff_tree be destructive. @@ -105,7 +128,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 +151,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 } @@ -141,36 +164,108 @@ class Gitalist::Git::Object::Commit } - method blame ( NonEmptySimpleStr $filename ) { + # XXX A prime candidate for caching. + method blame ( NonEmptySimpleStr $filename, SimpleStr $sha1 ) { my @blameout = $self->_run_cmd_list( - blame => '-p', $self->sha1, '--', $filename + blame => '-p', $sha1 ? $sha1 : $self->sha1, '--', $filename ); - my(%metadata, @filedata); + my(%commitdata, @filedata); while(defined(local $_ = shift @blameout)) { my ($sha1, $orig_lineno, $lineno, $group_size) = - /^([0-9a-f]{40}) (\d+) (\d+)(?: (\d+))?$/; + /^([0-9a-f]{40}) (\d+) (\d+)(?: (\d+))?$/; - my $meta = $metadata{$sha1} ||= { - orig_lineno => $orig_lineno, - lineno => $lineno, - group_size => $group_size, - }; + $commitdata{$sha1} = {} + unless exists $commitdata{$sha1}; + my $commit = $commitdata{$sha1}; my $line; - while(defined($line = shift @blameout)) { - last - if $line =~ s/^\t//; - $meta->{$1} = $2 - if $line =~ /^(\S+) (.*)/; + + until(@blameout == 0 || ($line = shift @blameout) =~ s/^\t//) { + $commit->{$1} = $2 if $line =~ /^(\S+) (.*)/; } - $meta->{parent} = $self->_run_cmd('rev-parse', "$sha1^") - unless exists $meta->{parent}; + unless(exists $commit->{author_dt}) { + for my $t (qw/author committer/) { + my $dt = DateTime->from_epoch(epoch => $commit->{"$t-time"}); + $dt->set_time_zone($commit->{"$t-tz"}); + $commit->{"$t\_dt"} = $dt; + } + } - push @filedata, { line => $line, sha1 => $sha1 }; + push @filedata, { + line => $line, + commit => { sha1 => $sha1, %$commit }, + meta => { + orig_lineno => $orig_lineno, + lineno => $lineno, + ( $group_size ? (group_size => $group_size) : () ), + }, + }; } - return \%metadata, \@filedata; + return \@filedata; } } + + +1; + +__END__ + +=head1 NAME + +Gitalist::Git::Object::Commit + +=head1 SYNOPSIS + + my $commit = Repository->get_object($commit_sha1); + +=head1 DESCRIPTION + +Represents a commit object in a git repository. +Subclass of C. + + +=head1 ATTRIBUTES + +=head2 committer + +=head2 committed_time + +=head2 author + +=head2 authored_time + +=head2 comment + +=head2 tree_sha1 + +=head2 parents + +=head2 parent_sha1 + +=head2 parent_sha1s + + +=head1 METHODS + +=head2 sha_by_path ($path) + +Returns the tree/file sha1 for a given path in a commit. + +=head2 get_patch + +=head2 diff + +=head2 blame + +=head1 AUTHORS + +See L for authors. + +=head1 LICENSE + +See L for the license. + +=cut