b5ba003b8fc4056c3748582d18ce89e65d687050
[scpubgit/System-Introspector-Report.git] / lib / System / Introspector / Report / Publish / MediaWiki.pm
1 package System::Introspector::Report::Publish::MediaWiki;
2 use Moo;
3 use Try::Tiny;
4 use Object::Remote;
5 use Object::Remote::Future;
6 use Log::Contextual::WarnLogger;
7 use Log::Contextual qw( :log ),
8   -default_logger => Log::Contextual::WarnLogger->new({
9     env_prefix => 'SI_REPORT_MEDIAWIKI',
10     levels      => [qw( error warn info debug trace )],
11   });
12
13 use aliased 'System::Introspector::Report::Publish::MediaWiki::Updater';
14
15 has page_options => (
16   is => 'ro',
17   default => sub { {} },
18   init_arg => 'page',
19 );
20
21 has process_count => (
22   is => 'ro',
23   isa => sub {
24     die "MediaWiki processes count has to be above 0\n"
25       if $_[0] < 1;
26   },
27   default => sub { 1 },
28   init_arg => 'processes',
29 );
30
31 has updater_pool => (
32   is => 'lazy',
33   init_arg => undef,
34 );
35
36 sub _build_updater_pool {
37   my ($self) = @_;
38   return [map {
39     Updater->new::on('-', $self->connect_info_pairs);
40   } 1 .. $self->process_count];
41 }
42
43 sub publish {
44   my ($self, $reports) = @_;
45   my $pages = $self->page_options;
46   log_info {
47     sprintf "Pushing reports to MediaWiki at '%s'", $self->api_uri;
48   };
49   for my $page (sort keys %$pages) {
50     my $options = $pages->{$page};
51     if ($page =~ m{\%\(meta:(.+?)\)}) {
52       $self->_publish_dynamic($reports, $page, $1, $options);
53     }
54     else {
55       $self->_publish_pages([$reports, $page, $options]);
56     }
57   }
58   log_info { "Finished pushing to MediaWiki" };
59   return 1;
60 }
61
62 sub _publish_pages {
63   my ($self, @pages) = @_;
64   my $stream = sub {
65     my $next = shift @pages
66       or return undef;
67     my ($reports, $page_name, $options) = @$next;
68     my $sorted = $self->_sort_reports($reports, $options->{report} || []);
69     return [$page_name, $options, $sorted];
70   };
71   await_all map {
72     $_->start::process($stream);
73   } @{ $self->updater_pool };
74 }
75
76 sub _sort_reports {
77   my ($self, $reports, $included) = @_;
78   my @matchers = map {
79     $self->_prepare_matcher_from($_);
80   } ref($included) ? @{$included} : $included;
81   my @grouped;
82   for my $report (@$reports) {
83     my ($group_idx) = grep {
84       $self->_match_id($report, $matchers[$_]);
85     } 0 .. $#matchers;
86     if (defined $group_idx) {
87       push @{$grouped[$group_idx]}, $report;
88     }
89   }
90   return [ map { (@$_) } @grouped ];
91 }
92
93 sub _publish_dynamic {
94   my ($self, $reports, $page_name, $key, $options) = @_;
95   my %reports_by_key;
96   for my $report (@$reports) {
97     my $value = $report->{meta}{$key};
98     next unless defined $value;
99     push @{ $reports_by_key{$value} ||= [] }, $report;
100   }
101   my @pages;
102   for my $value (keys %reports_by_key) {
103     (my $effective_page = $page_name)
104       =~ s{\%\(meta:\Q$key\E\)}{$value};
105     my $assoc = $reports_by_key{$value};
106     push @pages, [$assoc, $effective_page, $options];
107   }
108   $self->_publish_pages(@pages);
109   return 1;
110 }
111
112 with $_ for qw(
113   System::Introspector::Report::Publish::API
114   System::Introspector::Report::Publish::MediaWiki::HasConnectInfo
115 );
116
117 1;