class Gitalist::Git::Project {
# FIXME, use Types::Path::Class and coerce
use MooseX::Types::Common::String qw/NonEmptySimpleStr/;
- use MooseX::Types::Moose qw/Str Maybe/;
+ use MooseX::Types::Moose qw/Str Maybe Bool/;
use DateTime;
- use Path::Class;
+ use MooseX::Types::Path::Class qw/Dir/;
use Gitalist::Git::Util;
use aliased 'Gitalist::Git::Object';
our $SHA1RE = qr/[0-9a-fA-F]{40}/;
-
+
has name => ( isa => NonEmptySimpleStr,
is => 'ro', required => 1 );
- has path => ( isa => "Path::Class::Dir",
+ has path => ( isa => Dir,
is => 'ro', required => 1);
has description => ( isa => Str,
handles => [ 'run_cmd' ],
);
+ has project_dir => ( isa => Dir,
+ is => 'ro',
+ lazy => 1,
+ default => sub {
+ my $self = shift;
+ $self->is_bare
+ ? $self->path
+ : $self->path->subdir('.git')
+ },
+ );
+ has is_bare => (
+ isa => Bool,
+ is => 'ro',
+ lazy => 1,
+ default => sub {
+ my $self = shift;
+ -f $self->path->file('.git', 'HEAD')
+ ? 0
+ : -f $self->path->file('HEAD')
+ ? 1
+ : confess("Cannot find " . $self->path . "/.git/HEAD or "
+ . $self->path . "/HEAD");
+ },
+ );
+
method BUILD {
$self->$_() for qw/_util last_change owner description/; # Ensure to build early.
}
+ method _project_dir {
+ -f $self->{path}->file('.git', 'HEAD')
+ ? $self->{path}->subdir('.git')
+ : $self->{path};
+ }
+
method _build__util {
- my $util = Gitalist::Git::Util->new(
- gitdir => $self->project_dir($self->path),
+ Gitalist::Git::Util->new(
+ project => $self,
);
- return $util;
}
-
+
method _build_description {
my $description = "";
eval {
- $description = $self->path->file('description')->slurp;
+ $description = $self->project_dir->file('description')->slurp;
chomp $description;
};
return $description;
}
method _build_owner {
- my ($gecos, $name) = (getpwuid $self->path->stat->uid)[6,0];
+ my ($gecos, $name) = (getpwuid $self->project_dir->stat->uid)[6,0];
$gecos =~ s/,+$//;
return length($gecos) ? $gecos : $name;
}
-
+
method _build_last_change {
my $last_change;
my $output = $self->run_cmd(
return $last_change;
}
+ method heads {
+ my $cmdout = $self->run_cmd(qw/for-each-ref --sort=-committerdate /, '--format=%(objectname)%00%(refname)%00%(committer)', 'refs/heads');
+ my @output = $cmdout ? split(/\n/, $cmdout) : ();
+ my @ret;
+ for my $line (@output) {
+ my ($rev, $head, $commiter) = split /\0/, $line, 3;
+ $head =~ s!^refs/heads/!!;
+
+ push @ret, { sha1 => $rev, name => $head };
+
+ #FIXME: That isn't the time I'm looking for..
+ if (my ($epoch, $tz) = $line =~ /\s(\d+)\s+([+-]\d+)$/) {
+ my $dt = DateTime->from_epoch(epoch => $epoch);
+ $dt->set_time_zone($tz);
+ $ret[-1]->{last_change} = $dt;
+ }
+ }
+
+ return @ret;
+ }
+
+
=head2 head_hash
Find the hash of a given head (defaults to HEAD).
return @ret;
}
- # FIXME - Why not just stay in Path::Class land and return a P::C::D here?
- method project_dir {
- my $dir = $self->path->stringify;
- $dir .= '/.git'
- if -f dir($dir)->file('.git/HEAD');
- return $dir;
+ use Gitalist::Git::Object;
+ method get_object (Str $sha1) {
+ return Gitalist::Git::Object->new(
+ project => $self,
+ sha1 => $sha1,
+ );
+ }
+
+ # Should be in ::Object
+ method get_object_mode_string (Gitalist::Git::Object $object) {
+ return unless $object && $object->{mode};
+ return $object->{modestr};
+ }
+
+ method get_object_type ($object) {
+ chomp(my $output = $self->run_cmd(qw/cat-file -t/, $object));
+ return unless $output;
+
+ return $output;
+ }
+
+ method cat_file ($object) {
+ my $type = $self->get_object_type($object);
+ die "object `$object' is not a file\n"
+ if (!defined $type || $type ne 'blob');
+
+ my $output = $self->run_cmd(qw/cat-file -p/, $object);
+ return unless $output;
+
+ return $output;
}
+ method hash_by_path ($base, $path?, $type?) {
+ $path ||= '';
+ $path =~ s{/+$}();
+
+ my $output = $self->run_cmd('ls-tree', $base, '--', $path)
+ or return;
+ my($line) = $output ? split(/\n/, $output) : ();
+
+ #'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa panic.c'
+ $line =~ m/^([0-9]+) (.+) ($SHA1RE)\t/;
+ return defined $type && $type ne $2
+ ? ()
+ : $3;
+ }
+
+
+
# Compatibility
=head2 info
last_change => $self->last_change,
};
};
-
+
} # end class