7373df94e94f14c5ee57e511be6df5ed1029498c
[scpubgit/System-Introspector-Report.git] / lib / System / Introspector / Report / Source.pm
1 package System::Introspector::Report::Source;
2 use Moo;
3 use JSON::PP;
4 use IO::All;
5 use Module::Runtime qw( use_module );
6 use Log::Contextual qw( :log );
7
8 my $_json = JSON::PP->new->utf8->relaxed->allow_nonref;
9
10 has root => (is => 'ro', required => 1);
11
12 sub new_from_root {
13   my ($class, $root, @args) = @_;
14   if ($root =~ m{^(.+):(.+)$}) {
15     my ($remote, $remote_root) = ($1, $2);
16     require Object::Remote;
17     return $class->new::on($remote, @args, root => $remote_root);
18   }
19   else {
20     return $class->new(@args, root => $root);
21   }
22 }
23
24 sub generate {
25   my ($self, @types) = @_;
26   my @generators = map { $self->_make_generator($_) } @types;
27   my $required = +{ map { ($_ => 1) } map $_->required_data, @generators };
28   my @dirs = $self->_find_source_dirs;
29   for my $dir_spec (@dirs) {
30     my ($id, $path) = @$dir_spec;
31     my $data = $self->_load_dataset($path, $required)
32       or next;
33     log_trace { "loading node '$id' from '$path'" };
34     $_->collect_from($id, $data)
35       for @generators;
36   }
37   return map { ($_->render_reports) } @generators;
38 }
39
40 sub _load_dataset {
41   my ($self, $path, $required) = @_;
42   my $root = $self->root;
43   return +{
44     map {
45       ($_->[0], $_json->decode(scalar $_->[1]->slurp) || {});
46     } grep {
47       $required->{$_->[0]};
48     } map {
49       my $key = $_;
50       $key =~ s!^\Q$root\E/*(?:[^/]+/+){2}!!;
51       $key =~ s{\.json$}{};
52       [$key, $_];
53     } grep {
54       not(m{^\.}) and m{\.json$};
55     } $path->deep->all_files
56   };
57 }
58
59 sub _find_source_dirs {
60   my ($self) = @_;
61   my $root = $self->root;
62   return map {
63     (my $id = $_) =~ s{^\Q$root\E/*}{};
64     [$id, $_];
65   } io($root)->all_dirs;
66 }
67
68 sub _make_generator {
69   my ($self, $spec) = @_;
70   my ($type, $args) = @$spec;
71   return use_module("System::Introspector::Report::Builder::$type")
72     ->new($args || {});
73 }
74
75 1;