capture origin/<name> of active branch in case remote is not tracked
[scpubgit/System-Introspector.git] / lib / System / Introspector / Probe / Repositories / Git.pm
CommitLineData
afd7c030 1package System::Introspector::Probe::Repositories::Git;
5843e886 2use Moo;
3
1d5b2d19 4use System::Introspector::Util qw(
5 handle_from_command
6 transform_exceptions
7 lines_from_command
8);
9
e05a74d7 10has root => (
11 is => 'ro',
12 default => sub { '/' },
13);
14
5843e886 15sub gather {
16 my ($self) = @_;
1d5b2d19 17 return transform_exceptions {
18 my $pipe = $self->_open_locate_git_config_pipe;
19 my %location;
20 while (defined( my $line = <$pipe> )) {
21 chomp $line;
22 next unless $line =~ m{^(.+)/\.git/config$};
23 my $base = $1;
24 $location{ $base } = $self->_gather_git_info($line);
25 }
26 return { git => \%location };
27 };
5843e886 28}
29
30sub _gather_git_info {
31 my ($self, $config) = @_;
6a1a86c6 32 (my $git_dir = $config) =~ s{/config$}{};
5843e886 33 return {
1d5b2d19 34 config_file => $config,
6a1a86c6 35 current => transform_exceptions {
36 $self->_gather_current_state($git_dir);
37 },
1d5b2d19 38 config => transform_exceptions {
39 $self->_gather_git_config($config);
40 },
41 tracked => transform_exceptions {
6a1a86c6 42 $self->_gather_track_info($git_dir);
1d5b2d19 43 },
5843e886 44 };
45}
46
6a1a86c6 47sub _gather_current_state {
48 my ($self, $git_dir) = @_;
49 local $ENV{GIT_DIR} = $git_dir;
50 my ($active_branch) =
51 map { s{^\s*\*\s+}{}; $_ }
52 grep { m{^\s*\*\s+(.+)$} }
53 lines_from_command ['git', 'branch'];
54 return { __error__ => 'No active branch' }
55 unless $active_branch;
56 my @log_lines = lines_from_command [
57 'git', 'log',
58 '-n1',
59 '--date=iso',
60 '--pretty=fuller',
61 ];
62 return {
63 branch => $active_branch,
64 commit => [@log_lines],
356497ee 65 origin => transform_exceptions {
66 my $count = $self->_find_commit_count(
67 $git_dir,
68 $active_branch,
69 "origin/$active_branch",
70 );
71 return {
72 local_commit_count => $count,
73 };
74 },
6a1a86c6 75 };
76}
77
e05a74d7 78sub _gather_track_info {
6a1a86c6 79 my ($self, $git_dir) = @_;
1d5b2d19 80 return $self->_find_tracking($git_dir);
e05a74d7 81}
82
83sub _find_tracking {
84 my ($self, $dir) = @_;
1d5b2d19 85 local $ENV{GIT_DIR} = $dir;
86 my @lines = lines_from_command
87 ['git', 'for-each-ref',
1eff200c 88 '--format', q{OK %(refname:short) %(upstream:short)},
1d5b2d19 89 'refs/heads',
90 ];
e05a74d7 91 my %branch;
92 for my $line (@lines) {
93 if ($line =~ m{^OK\s+(\S+)\s+(\S+)?$}) {
94 my ($local, $remote) = ($1, $2);
95 $branch{ $local } = {
96 upstream => $remote,
1d5b2d19 97 changed_files => transform_exceptions {
98 $self->_find_changes($dir, $local, $remote);
99 },
100 local_commit_count => transform_exceptions {
c7c98588 101 $self->_find_commit_count($dir, $local, $remote);
1d5b2d19 102 },
e05a74d7 103 }
104 }
105 else {
8b69d66e 106 return { __error__ => join "\n", @lines };
e05a74d7 107 }
108 }
109 return { branches => \%branch };
110}
111
c7c98588 112sub _find_commit_count {
e05a74d7 113 my ($self, $dir, $local, $remote) = @_;
8b69d66e 114 return { __error__ => "No remote" }
e05a74d7 115 unless defined $remote;
1d5b2d19 116 local $ENV{GIT_DIR} = $dir;
117 my @lines = lines_from_command
118 ['git', 'log', '--oneline', "$remote..$local"];
c7c98588 119 return scalar @lines;
e05a74d7 120}
121
122sub _find_changes {
123 my ($self, $dir, $local, $remote) = @_;
8b69d66e 124 return { __error__ => "No remote" }
e05a74d7 125 unless defined $remote;
1d5b2d19 126 local $ENV{GIT_DIR} = $dir;
127 my @lines = lines_from_command
128 ['git', 'diff', '--name-only', $local, $remote];
1b608727 129 return \@lines;
e05a74d7 130}
131
5843e886 132sub _gather_git_config {
133 my ($self, $config) = @_;
134 my $pipe = $self->_open_git_config_pipe($config);
135 my %config;
136 while (defined( my $line = <$pipe> )) {
137 chomp $line;
138 my ($name, $value) = split m{=}, $line, 2;
139 $config{ $name } = $value;
140 }
1d5b2d19 141 return { contents => \%config };
5843e886 142}
143
144sub _open_git_config_pipe {
145 my ($self, $config) = @_;
1d5b2d19 146 return handle_from_command "git config --file $config --list";
5843e886 147}
148
149sub _open_locate_git_config_pipe {
150 my ($self) = @_;
1d5b2d19 151 (my $root = $self->root) =~ s{/$}{};
152 return handle_from_command sprintf
153 q{locate --regex '^%s/.*\\.git/config$'}, $root;
5843e886 154}
155
1561;
535e84b6 157
158__END__
159
160=head1 NAME
161
f24afb0e 162System::Introspector::Probe::Repositories::Git - Gather Git repository info
535e84b6 163
164=head1 DESCRIPTION
165
166Find Git repositories and gathers their information.
167
168=head1 ATTRIBUTES
169
170=head2 root
171
172This is the root path for the search of git directories. Defaults to C</>.
173
174=head1 SEE ALSO
175
176=over
177
178=item L<System::Introspector>
179
180=back
181
f24afb0e 182=head1 COPYRIGHT
183
184Copyright (c) 2012 the L<System::Introspector>
185L<AUTHOR|System::Introspector/AUTHOR>,
186L<CONTRIBUTORS|System::Introspector/CONTRIBUTORS> and
187L<SPONSORS|System::Introspector/SPONSORS>.
188
189=head1 LICENSE
535e84b6 190
f24afb0e 191This library is free software and may be distributed under the same terms
192as perl itself.
193
194=cut