Start work splitting out Gitalist::Model::Git into smaller pieces.
[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
9     has name => ( isa => NonEmptySimpleStr,
10                   is => 'ro' );
11     has path => ( isa => "Path::Class::Dir",
12                   is => 'ro');
13
14     has description => ( isa => NonEmptySimpleStr,
15                          is => 'ro',
16                          lazy_build => 1,
17                      );
18     has owner => ( isa => NonEmptySimpleStr,
19                    is => 'ro',
20                    lazy_build => 1,
21                );
22     has last_change => ( isa => 'DateTime',
23                          is => 'ro',
24                          lazy_build => 1,
25                      );
26
27     
28     method _build_description {
29         my $description = $self->path->file('description')->slurp;
30         chomp $description;
31         return $description;
32     }
33
34     method _build_owner {
35         my $owner = (getpwuid $self->path->stat->uid)[6];
36         $owner =~ s/,+$//;
37         return $owner;
38     }
39     
40     method _build_last_change {
41         my $last_change;
42         my $output = $self->run_cmd(
43             qw{ for-each-ref --format=%(committer)
44                 --sort=-committerdate --count=1 refs/heads
45           });
46         if (my ($epoch, $tz) = $output =~ /\s(\d+)\s+([+-]\d+)$/) {
47             my $dt = DateTime->from_epoch(epoch => $epoch);
48             $dt->set_time_zone($tz);
49             $last_change = $dt;
50         }
51         return $last_change;
52     }
53
54
55 =head2 run_cmd
56
57 Call out to the C<git> binary and return a string consisting of the output.
58
59 =cut
60
61         method run_cmd (@args) {
62             unshift @args, ( '--git-dir' => $self->path );
63             print STDERR 'RUNNING: ', $self->_git, qq[ @args], $/;
64
65             open my $fh, '-|', $self->_git, @args
66                 or die "failed to run git command";
67             binmode $fh, ':encoding(UTF-8)';
68
69             my $output = do { local $/ = undef; <$fh> };
70             close $fh;
71
72             return $output;
73         }
74
75     has _git      => ( isa => NonEmptySimpleStr, is => 'ro', lazy_build => 1 );
76     use File::Which;
77     method _build__git {
78         my $git = File::Which::which('git');
79
80         if (!$git) {
81             die <<EOR;
82 Could not find a git executable.
83 Please specify the which git executable to use in gitweb.yml
84 EOR
85         }
86
87         return $git;
88     }
89     has _gpp      => ( isa => 'Git::PurePerl',   is => 'rw', lazy_build => 1 );
90     use Git::PurePerl;
91     method _build__gpp {
92         my $gpp = Git::PurePerl->new(gitdir => $self->path);
93         return $gpp;
94     }
95
96     method project_dir (Path::Class::Dir $project) {
97         my $dir = $project->stringify;
98         $dir .= '/.git'
99             if -f dir($dir)->file('.git/HEAD');
100         return $dir;
101     }
102
103     
104     # Compatibility
105
106 =head2 project_info
107
108 Returns a hash containing properties of this project. The keys will
109 be:
110
111         name
112         description (empty if .git/description is empty/unnamed)
113         owner
114         last_change
115
116 =cut
117
118     method project_info {
119         return {
120             name => $self->name,
121             description => $self->description,
122             owner => $self->owner,
123             last_change => $self->last_change,
124         };
125     };
126     
127 } # end class