--- /dev/null
+package System::Introspector::LibDirs::Perl;
+use Moo;
+use Module::Metadata;
+use Digest::SHA;
+
+has root => (
+ is => 'ro',
+ default => sub { '/' },
+);
+
+sub gather {
+ my ($self) = @_;
+ my $pipe = $self->_open_locate_libdirs_pipe;
+ my %libdir;
+ while (defined( my $line = <$pipe> )) {
+ chomp $line;
+ $libdir{ $line } = $self->_gather_libdir_info($line);
+ }
+ return \%libdir;
+}
+
+sub _gather_libdir_info {
+ my ($self, $libdir) = @_;
+ my %module;
+ my $pipe = $self->_open_locate_pm_pipe($libdir);
+ while (defined( my $line = <$pipe> )) {
+ chomp $line;
+ my $metadata = Module::Metadata->new_from_file($line);
+ next unless $metadata->name;
+ my $sha = Digest::SHA->new(256);
+ $sha->addfile($line);
+ push @{ $module{ $metadata->name } //= [] }, {
+ file => $line,
+ version => $metadata->version,
+ size => scalar(-s $line),
+ sha256_hex => $sha->hexdigest,
+ };
+ }
+ return \%module;
+}
+
+sub _open_locate_pm_pipe {
+ my ($self, $libdir) = @_;
+ my $command = sprintf
+ q{find %s -name '*.pm'},
+ $libdir;
+ open my $pipe, '-|', $command
+ or die "Unable to open pipe to '$command': $!\n";
+ return $pipe;
+}
+
+sub _open_locate_libdirs_pipe {
+ my ($self) = @_;
+ my $root = $self->root;
+ $root .= '/'
+ unless $root =~ m{/$};
+ my $command = sprintf
+ q{locate --regex '^%s.*lib/perl5$'},
+ $root;
+ open my $pipe, '-|', $command
+ or die "Unable to open pipe to '$command': $!\n";
+ return $pipe;
+}
+
+1;