]> git.openstreetmap.org Git - rails.git/blob - script/misc/update-wiki-pages
update-wiki-pages: adding retry and timeout
[rails.git] / script / misc / update-wiki-pages
1 #!/usr/bin/env perl
2 use 5.010;
3 use strict;
4 use warnings;
5
6 use Getopt::Long;
7 use Pod::Usage;
8 use MediaWiki::API;
9 use Test::More qw(no_plan);
10 use YAML::XS qw(Dump);
11
12 =head1 NAME
13
14 update-wiki-pages - Scrape the wiki for key/value wiki description pages
15
16 =head1 SYNOPSIS
17
18     perl script/misc/update-wiki-pages config/wiki_pages.yml 
19
20 Or with prove(1):
21
22     prove -e 'perl script/misc/update-wiki-pages' config/wiki_pages.yml
23
24 =cut
25
26 # Get the command-line options
27 Getopt::Long::Parser->new(
28     config => [ qw< bundling no_ignore_case no_require_order pass_through > ],
29 )->getoptions(
30     'h|help' => \my $help,
31 ) or help();
32
33 # On --help
34 help() if $help;
35
36 my $out_file = $ARGV[0];
37 $out_file //= 'config/wiki_pages.yml';
38
39 help() unless -f $out_file;
40
41 # Get a API interface
42 my $mw = MediaWiki::API->new();
43 ok($mw, "Got a MediaWiki API");
44 $mw->{config}->{api_url} = 'https://wiki.openstreetmap.org/w/api.php';
45 $mw->{config}->{retries} = 5;
46 $mw->{config}->{retry_delay} = 30;
47
48 # All our goodies
49 my (%feature, %count);
50
51 # This is what you get on:
52 ## http://wiki.openstreetmap.org/w/index.php?search=Template:KeyDescription&fulltext=Search&fulltext=Search
53 for my $lang ('', map { "${_}:" } qw[ Pt Fi De It HU Cz Fr RU Pl ]) {
54     ok(1, "  Templates for language '$lang'");
55
56     # Key pages
57     ok(1, "    Getting key pages");
58     my $cnt = stick_content_in_hash("key", "Template:${lang}KeyDescription", \%feature);
59     $cnt += stick_content_in_hash("key", "Template:${lang}Feature", \%feature);
60     ok(1, "    Got $cnt key pages");
61     $count{key} += $cnt;
62
63     # Value pages
64     ok(1, "    Getting value pages");
65     $cnt = stick_content_in_hash("tag", "Template:${lang}ValueDescription", \%feature);
66     ok(1, "    Got $cnt value pages");
67     $count{value} += $cnt;
68 }
69
70 ok(1, "Got a total of $count{$_} ${_}s") for qw[ key value ];
71
72 # Dump to .yml file
73 open my $out, ">", $out_file or die "Can't open file '$out_file' supplied on the command line";
74 say $out "# THIS FILE IS AUTOGENERATED WITH THE script/misc/update-wiki-pages";
75 say $out "# PROGRAM DO NOT MANUALLY EDIT IT";
76 say $out "";
77 say $out Dump(\%feature);
78 close $out;
79
80 exit 0;
81
82 sub stick_content_in_hash
83 {
84     my ($key, $title, $hash) = @_;
85     my $ukey = ucfirst $key;
86
87     my $space_to_underscore = sub {
88         my $txt = shift;
89         $txt =~ s/ /_/g;
90         $txt;
91     };
92
93     my $count = 0;
94
95     my $process_link = sub {
96         my $link = shift;
97         $count++;
98         ok(1, "    ... got $count links") if $count % 200 == 0;
99         my $title = $link->{title};
100         my $lang;
101         my $key_name;
102         if ($title =~ /^$ukey:(?<key_name>.*?)$/) {
103             # English by default
104             $lang = "en";
105             $key_name = $space_to_underscore->($+{key_name});
106         } elsif ($title =~ /^(?<lang>[^:]+):$ukey:(?<key_name>.*?)$/) {
107             $lang = lc $+{lang};
108             $key_name = $space_to_underscore->($+{key_name});
109         }
110         if ($lang && !exists($hash->{$lang}->{$key}->{$key_name})) {
111             $hash->{$lang}->{$key}->{$key_name} = $title;
112         }
113     };
114
115     get_embeddedin(
116         $title,
117         sub {
118             my $link = shift;
119             $process_link->($link);
120             get_redirects(
121                 $link->{title},
122                 sub {
123                     my $link = shift;
124                     $process_link->($link) if exists($link->{redirect});
125                 }
126             );
127         }
128     );
129
130     return $count;
131 }
132
133 sub process_list
134 {
135     my $callback = shift;
136     my $links = shift;
137     for my $link (@$links) {
138         $callback->($link);
139     }
140 }
141
142 sub get_embeddedin
143 {
144     my ($title, $callback) = @_;
145     my $articles = $mw->list(
146         {
147             action => 'query',
148             list => 'embeddedin',
149             eititle => $title,
150             eifilterredir => 'nonredirects',
151             # Doesn't work for De:* and anything non-en. Odd.
152             # einamespace => '0|8',
153             eilimit => '200',
154         },
155         {
156             max => '0',
157             hook => sub { process_list($callback, @_) },
158             skip_encoding => 1,
159         }
160     ) || die $mw->{error}->{code} . ': ' . $mw->{error}->{details};
161 }
162
163 sub get_redirects
164 {
165     my ($title, $callback) = @_;
166     my $articles = $mw->list(
167         {
168             action => 'query',
169             list => 'backlinks',
170             bltitle => $title,
171             blfilterredir => 'redirects',
172             # Doesn't work for De:* and anything non-en. Odd.
173             # einamespace => '0|8',
174             bllimit => '200',
175         },
176         {
177             max => '0',
178             hook => sub { process_list($callback, @_) },
179             skip_encoding => 1,
180         }
181     ) || die $mw->{error}->{code} . ': ' . $mw->{error}->{details};
182 }
183
184 sub help
185 {
186     my %arg = @_;
187
188     Pod::Usage::pod2usage(
189         -verbose => $arg{ verbose },
190         -exitval => $arg{ exitval } || 0,
191     );
192 }