/usr/local/CPAN/VCI/VCI/VCS/Git/Commit.pm
package VCI::VCS::Git::Commit;
use Moose;
extends 'VCI::Abstract::Commit';
has 'x_changes' => (is => 'ro', lazy_build => 1);
# Moose doesn't let me do lazy_build here, as of Moose 0.33.
has '+message' => (lazy => 1, default => sub { shift->_build_message });
sub _build_message {
my $self = shift;
my $text = $self->project->x_do('log', ['-1', '--pretty=medium',
$self->revision], 1);
# Everything before the message ends in two newlines.
$text =~ s/^.+\n\n//s;
# Also, every line is idented by four spaces.
$text =~ s/^\s{4}//mg;
# If Git's "subject" or "body" are empty, it prints "<unknown>"
$text =~ s/^<unknown>\n//s;
$text =~ s/\n<unknown>$//s;
chomp($text);
return $text;
}
sub _build_added { return shift->_x_files_from_changes('A') }
sub _build_removed { return shift->_x_files_from_changes('D') }
sub _build_modified { return shift->_x_files_from_changes('M') }
sub _build_moved { return shift->_x_hash_from_changes('R') }
sub _build_copied { return shift->_x_hash_from_changes('C') }
sub _build_as_diff {
my $self = shift;
my $diff = $self->project->x_do('whatchanged',
['-m', '-p', '-1', '-C', '--pretty=format:', $self->revision], 1);
return $self->diff_class->new(raw => $diff, project => $self->project);
}
sub _x_files_from_changes {
my ($self, $type) = @_;
my $files = $self->x_changes->{$type};
(print STDERR "Creating " . scalar @$files . " $type file objects...\n")
if $self->vci->debug;
return [map { $self->file_class->new(path => $_, project => $self->project,
revision => $self->revision) }
@$files];
}
sub _x_hash_from_changes {
my ($self, $type) = @_;
my $details = $self->x_changes->{$type};
if ($self->vci->debug) {
print STDERR "Creating " . scalar(keys %$details)
. " $type file objects...\n";
}
my %result;
foreach my $new_name (keys %$details) {
my %params = %{ $details->{$new_name} };
$result{$new_name} =
$self->file_class->new(%params, project => $self->project);
}
return \%result;
}
sub _build_x_changes {
my $self = shift;
my $output = $self->project->x_do('whatchanged',
['-m', '-1', '-C', '--pretty=format:%P', $self->revision]);
my (%moved, %copied);
my %actions = ('A' => [], 'M' => [], 'D' => [],
'C' => \%copied, 'R' => \%moved);
my @parents = split(' ', shift @$output) if @$output;
foreach my $line (@$output) {
# The format of this line is described in the git-diff-tree manpage.
$line =~ /^:\d+ \d+ (\w+)\.* (\w+)\.* (\w)(\d+)?\t([^\t]+)(\t(.*))?$/o;
my ($sha1, $sha2, $type, $file, $new_name) = ($1, $2, $3, $5, $7);
if ($type eq 'C') {
$copied{$new_name} = { path => $file, x_one_of => \@parents };
if ($sha1 eq $sha2) {
push(@{ $actions{'A'} }, $new_name);
}
else {
push(@{ $actions{'M'} }, $new_name);
}
}
elsif ($type eq 'R') {
$moved{$new_name} = { path => $file, x_one_of => \@parents };
if ($sha1 ne $sha2) {
push(@{ $actions{'M'} }, $new_name);
}
}
else {
push(@{ $actions{$type} }, $file);
}
}
return \%actions;
}
__PACKAGE__->meta->make_immutable;
1;