initial version with mediawiki produce/parse, three reports, missing update-merger
[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
7 my $_json = JSON::PP->new->utf8->relaxed->allow_nonref;
8
9 has root => (is => 'ro', required => 1);
10
11 sub new_from_root {
12   my ($class, $root, @args) = @_;
13   if ($root =~ m{^(.+):(.+)$}) {
14     my ($remote, $remote_root) = ($1, $2);
15     require Object::Remote;
16     return $class->new::on($remote, @args, root => $remote_root);
17   }
18   else {
19     return $class->new(@args, root => $root);
20   }
21 }
22
23 sub generate {
24   my ($self, @types) = @_;
25   my @generators = map { $self->_make_generator($_) } @types;
26   my $required = +{ map { ($_ => 1) } map $_->required_data, @generators };
27   my @dirs = $self->_find_source_dirs;
28   for my $dir_spec (@dirs) {
29     my ($id, $path) = @$dir_spec;
30     my $data = $self->_load_dataset($path, $required)
31       or next;
32     $_->collect_from($id, $data)
33       for @generators;
34   }
35   return map { ($_->render_reports) } @generators;
36 }
37
38 sub _load_dataset {
39   my ($self, $path, $required) = @_;
40   my $root = $self->root;
41   return +{
42     map {
43       ($_->[0], $_json->decode(scalar $_->[1]->slurp) || {});
44     } grep {
45       $required->{$_->[0]};
46     } map {
47       my $key = $_;
48       $key =~ s!^\Q$root\E/*(?:[^/]+/+){2}!!;
49       $key =~ s{\.json$}{};
50       [$key, $_];
51     } grep {
52       not(m{^\.}) and m{\.json$};
53     } $path->deep->all_files
54   };
55 }
56
57 sub _find_source_dirs {
58   my ($self) = @_;
59   my $root = $self->root;
60   return map {
61     (my $id = $_) =~ s{^\Q$root\E/*}{};
62     [$id, $_];
63   } io($root)->all_dirs;
64 }
65
66 sub _make_generator {
67   my ($self, $spec) = @_;
68   my ($type, $args) = @$spec;
69   return use_module("System::Introspector::Report::Builder::$type")
70     ->new($args || {});
71 }
72
73 1;