Added head_hash method to Project, and some test cleanups.
[catagits/Gitalist.git] / lib / Gitalist / Git / Project.pm
1 use MooseX::Declare;
2
3 class Gitalist::Git::Project {
4     # FIXME, use Types::Path::Class and coerce
5     use MooseX::Types::Common::String qw/NonEmptySimpleStr/;
6     use DateTime;
7     use Path::Class;
8     use Gitalist::Git::Util;
9
10     our $SHA1RE = qr/[0-9a-fA-F]{40}/;
11     
12     has name => ( isa => NonEmptySimpleStr,
13                   is => 'ro' );
14     has path => ( isa => "Path::Class::Dir",
15                   is => 'ro');
16
17     has description => ( isa => NonEmptySimpleStr,
18                          is => 'ro',
19                          lazy_build => 1,
20                      );
21     has owner => ( isa => NonEmptySimpleStr,
22                    is => 'ro',
23                    lazy_build => 1,
24                );
25     has last_change => ( isa => 'DateTime',
26                          is => 'ro',
27                          lazy_build => 1,
28                      );
29     has _util => ( isa => 'Gitalist::Git::Util',
30                    is => 'ro',
31                    lazy_build => 1,
32                    handles => [ 'run_cmd' ],
33                );
34
35     method _build__util {
36         my $util = Gitalist::Git::Util->new(
37             gitdir => $self->path,
38         );
39         return $util;
40     }
41     
42     method _build_description {
43         my $description = $self->path->file('description')->slurp;
44         chomp $description;
45         return $description;
46     }
47
48     method _build_owner {
49         my $owner = (getpwuid $self->path->stat->uid)[6];
50         $owner =~ s/,+$//;
51         return $owner;
52     }
53     
54     method _build_last_change {
55         my $last_change;
56         my $output = $self->run_cmd(
57             qw{ for-each-ref --format=%(committer)
58                 --sort=-committerdate --count=1 refs/heads
59           });
60         if (my ($epoch, $tz) = $output =~ /\s(\d+)\s+([+-]\d+)$/) {
61             my $dt = DateTime->from_epoch(epoch => $epoch);
62             $dt->set_time_zone($tz);
63             $last_change = $dt;
64         }
65         return $last_change;
66     }
67
68 =head2 head_hash
69
70 Find the hash of a given head (defaults to HEAD).
71
72 =cut
73
74     method head_hash (Str $head?) {
75         my $output = $self->run_cmd(qw/rev-parse --verify/, $head || 'HEAD' );
76         return unless defined $output;
77
78         my($sha1) = $output =~ /^($SHA1RE)$/;
79         return $sha1;
80     }
81
82     method project_dir (Path::Class::Dir $project) {
83         my $dir = $project->stringify;
84         $dir .= '/.git'
85             if -f dir($dir)->file('.git/HEAD');
86         return $dir;
87     }
88
89     # Compatibility
90
91 =head2 project_info
92
93 Returns a hash containing properties of this project. The keys will
94 be:
95
96         name
97         description (empty if .git/description is empty/unnamed)
98         owner
99         last_change
100
101 =cut
102
103     method project_info {
104         return {
105             name => $self->name,
106             description => $self->description,
107             owner => $self->owner,
108             last_change => $self->last_change,
109         };
110     };
111     
112 } # end class