Abstracted kludges a little more.
[catagits/Gitalist.git] / lib / Gitalist / Git / Object.pm
1 use MooseX::Declare;
2 use Moose::Autobox;
3
4 class Gitalist::Git::Object {
5     use MooseX::Types::Moose qw/Str Int Bool Maybe ArrayRef/;
6     use MooseX::Types::Common::String qw/NonEmptySimpleStr/;
7
8     use Fcntl ':mode';
9     use constant {
10         S_IFINVALID => 0030000,
11         S_IFGITLINK => 0160000,
12     };
13
14     BEGIN {
15         no warnings;
16         *S_ISLNK = sub ($) {}
17             if $^O eq 'MSWin32';
18     }
19
20     # repository and sha1 are required initargs
21     has repository => ( isa => 'Gitalist::Git::Repository',
22                      required => 1,
23                      is => 'ro',
24                      weak_ref => 1,
25                      handles => {
26                          _run_cmd => 'run_cmd',
27                          _run_cmd_fh => 'run_cmd_fh',
28                          _run_cmd_list => 'run_cmd_list',
29                          _get_gpp_object => 'get_gpp_object',
30                      },
31                  );
32     has sha1 => ( isa => NonEmptySimpleStr,
33                   required => 1,
34                   is => 'ro' );
35
36     has type => ( isa => NonEmptySimpleStr,
37                   is => 'ro',
38                   required => 1 );
39
40     has $_ => ( isa => NonEmptySimpleStr,
41                 required => 1,
42                 is => 'ro',
43                 lazy_build => 1 )
44         for qw/modestr size/;
45
46     has _gpp_obj => ( isa => 'Git::PurePerl::Object',
47                       required => 1,
48                       is => 'ro',
49                       lazy_build => 1,
50                       handles => [ 'content',
51                                ],
52                   );
53
54     # objects can't determine their mode or filename
55     has file => ( isa => NonEmptySimpleStr,
56                   required => 0,
57                   is => 'ro' );
58     has mode => ( isa => Int,
59                   required => 1,
60                   default => 0,
61                   is => 'ro' );
62
63     method BUILD { $self->$_() for qw/_gpp_obj size modestr/ }
64
65 ## Private methods
66
67 ## Builders
68     method _build__gpp_obj {
69         return $self->_get_gpp_object($self->sha1)
70     }
71
72     method "_build_size" {
73         my $v = $self->_cat_file_with_flag('s');
74         chomp($v);
75         return $v;
76     }
77
78     method _cat_file_with_flag ($flag) {
79         $self->_run_cmd('cat-file', '-' . $flag, $self->{sha1})
80     }
81
82     method _build_modestr {
83         # XXX The POSIX constants make win32 sad :(
84         return _mode_str($self->mode);
85     }
86
87     # via gitweb.pm
88     # submodule/subrepository, a commit object reference
89     sub S_ISGITLINK($) {
90         return (($_[0] & S_IFMT) == S_IFGITLINK)
91     }
92
93     # convert file mode in octal to symbolic file mode string
94     sub _mode_str {
95         my $mode = shift;
96
97         if (S_ISGITLINK($mode)) {
98             return 'm---------';
99         } elsif (S_ISDIR($mode & S_IFMT)) {
100             return 'drwxr-xr-x';
101         } elsif (S_ISLNK($mode)) {
102             return 'lrwxrwxrwx';
103         } elsif (S_ISREG($mode)) {
104             # git cares only about the executable bit
105             if ($mode & S_IXUSR) {
106                 return '-rwxr-xr-x';
107             } else {
108                 return '-rw-r--r--';
109             }
110         } else {
111             return '----------';
112         }
113     }
114
115 } # end class
116
117 __END__
118
119 =head1 NAME
120
121 Gitalist::Git::Object - Model of a git object.
122
123 =head1 SYNOPSIS
124
125     my $object = Repository->get_object($sha1);
126
127 =head1 DESCRIPTION
128
129 Abstract base class for git objects.
130
131
132 =head1 ATTRIBUTES
133
134
135 =head1 METHODS
136
137
138 =head1 AUTHORS
139
140 See L<Gitalist> for authors.
141
142 =head1 LICENSE
143
144 See L<Gitalist> for the license.
145
146 =cut