]>
Commit | Line | Data |
---|---|---|
aa99b349 DM |
1 | #!/usr/bin/perl |
2 | ||
3 | use strict; | |
4 | use warnings; | |
835dd63b DM |
5 | use Getopt::Long; |
6 | use File::Path; | |
7 | use File::Basename; | |
8 | use IO::File; | |
9 | ||
aa99b349 DM |
10 | use JSON; |
11 | ||
835dd63b DM |
12 | my $release = '@RELEASE@'; |
13 | ||
14 | my $clicmd = shift or | |
15 | die "no command specified\n"; | |
16 | ||
aa99b349 DM |
17 | my $data_str = ""; |
18 | while (<main::DATA>) { $data_str .= $_; } | |
19 | ||
20 | my $fileinfo = decode_json($data_str); | |
aa99b349 | 21 | |
835dd63b DM |
22 | my $tmpprefix = ".asciidoc-pve-tmp_"; |
23 | ||
24 | my $adoc_source_dir = "/usr/share/pve-doc-generator"; | |
25 | ||
26 | # inside pve-docs source dir? | |
27 | if (-f "attributes.txt" && -f "pve-admin-guide.adoc") { | |
28 | $adoc_source_dir = "." | |
29 | } | |
30 | ||
31 | my $prepared_files = {}; | |
32 | ||
c38115e9 | 33 | my $man_target_html = 0; |
835dd63b DM |
34 | my $env_stack = []; |
35 | my $env_skip = 0; | |
36 | ||
37 | sub push_environment { | |
38 | my ($env, $skip) = @_; | |
39 | ||
40 | $skip = 1 if $env_skip; | |
41 | $skip = 0 if !defined($skip); | |
42 | ||
43 | push @$env_stack, [$env, $skip]; | |
44 | ||
45 | $env_skip = $skip; | |
46 | } | |
47 | ||
48 | sub pop_environment { | |
49 | my ($env) = @_; | |
50 | ||
51 | my $last_stack_entry = pop @$env_stack; | |
52 | die "unable to pop env '$env'" if !defined($last_stack_entry); | |
53 | ||
54 | my ($last_env, $skip) = @$last_stack_entry; | |
55 | die "environment missmatch (${last_env} != $env)\n" if $last_env ne $env; | |
56 | ||
57 | if (!scalar(@$env_stack)) { | |
58 | $env_skip = 0; | |
59 | } else { | |
60 | my (undef, $skip) = @{$env_stack->[-1]}; | |
61 | $env_skip = $skip; | |
62 | } | |
63 | } | |
64 | ||
17d8be0c DM |
65 | sub cleanup { |
66 | ||
67 | # TODO: anything ? | |
68 | } | |
69 | ||
835dd63b DM |
70 | sub replace_wiki_xref { |
71 | my ($blockid, $text) = @_; | |
72 | ||
73 | my $link = $fileinfo->{blockid_target}->{wiki}->{$blockid}; | |
45930831 | 74 | my $reftext = $fileinfo->{reftext}->{wiki}->{$blockid}; |
835dd63b DM |
75 | |
76 | die "unable to resolve wiki link (xref:$blockid)\n" | |
77 | if !defined($link); | |
78 | ||
45930831 DM |
79 | $text = $reftext if !length($text); |
80 | ||
c38115e9 | 81 | die "xref: no text for wiki link '$blockid'\n" if !$text; |
508e0012 | 82 | |
835dd63b DM |
83 | return "$link\[$text\]"; |
84 | } | |
85 | ||
c38115e9 DM |
86 | sub replace_default_xref { |
87 | my ($blockid, $text) = @_; | |
88 | ||
89 | my $link = $fileinfo->{blockid_target}->{default}->{$blockid}; | |
90 | my $reftext = $fileinfo->{reftext}->{default}->{$blockid}; | |
91 | ||
92 | die "unable to resolve chapter link (xref:$blockid)\n" | |
93 | if !defined($link); | |
94 | ||
95 | $text = $reftext if !length($text); | |
96 | ||
97 | die "xref: no text for chapter link '$blockid'\n" if !$text; | |
98 | ||
99 | return "$link\[$text\]"; | |
100 | } | |
101 | ||
102 | sub replace_man_xref { | |
103 | my ($blockid, $text) = @_; | |
104 | ||
105 | my $link = $fileinfo->{blockid_target}->{manvolnum}->{$blockid}; | |
106 | my $reftext = $fileinfo->{reftext}->{manvolnum}->{$blockid}; | |
107 | ||
108 | die "unable to resolve man page link (xref:$blockid)\n" | |
109 | if !defined($link); | |
110 | ||
111 | $text = $reftext if !length($text); | |
112 | ||
113 | die "xref: no text for man page link '$blockid'\n" if !$text; | |
114 | ||
115 | my $section = $fileinfo->{mansection}->{manvolnum}->{$link}; | |
116 | die "link target is not a manual page" if !defined($section); | |
117 | ||
118 | ||
119 | if (0 && $man_target_html) { | |
120 | my $target = $link; | |
121 | $target =~ s/\.adoc//; | |
122 | $target .= ".$section"; | |
123 | return "link:${target}.html#${blockid}\[$text\]"; | |
124 | } else { | |
125 | my $command = $link; | |
126 | $command =~ s/\.adoc//; | |
127 | return "\*${text}\* (man \*${command}\*($section))"; | |
128 | } | |
129 | } | |
130 | ||
a22a4a80 DM |
131 | sub replace_xref { |
132 | my ($env, $blockid, $text) = @_; | |
835dd63b | 133 | |
a22a4a80 DM |
134 | if ($env eq 'wiki') { |
135 | return replace_wiki_xref($blockid, $text); | |
c38115e9 DM |
136 | } elsif ($env eq 'manvolnum') { |
137 | return replace_man_xref($blockid, $text); | |
138 | } elsif ($env eq 'default') { | |
139 | return replace_default_xref($blockid, $text); | |
a22a4a80 | 140 | } else { |
c38115e9 | 141 | die "internal error"; |
a22a4a80 DM |
142 | } |
143 | } | |
144 | ||
145 | sub prepare_adoc_file { | |
146 | my ($target_env, $filename, $attributes) = @_; | |
508e0012 | 147 | |
c38115e9 | 148 | return $prepared_files->{$filename} if defined($prepared_files->{$filename}); |
835dd63b DM |
149 | |
150 | print "PREPARE $filename\n"; | |
151 | ||
835dd63b DM |
152 | my $dirname = dirname($filename); |
153 | my $basename = basename($filename); | |
154 | ||
155 | my $outfilename = "$dirname/${tmpprefix}$basename"; | |
156 | ||
c38115e9 DM |
157 | $prepared_files->{$filename} = $outfilename; |
158 | ||
835dd63b DM |
159 | my $fh = IO::File->new("$filename", "r") or |
160 | die "unable to open file '$filename' - $!\n"; | |
161 | ||
162 | my $outfh = IO::File->new("$outfilename", "w") or | |
163 | die "unable to open temporary file '$outfilename'\n"; | |
164 | ||
165 | while (defined (my $line = <$fh>)) { | |
c38115e9 | 166 | chomp $line; |
835dd63b DM |
167 | if ($line =~ m/^if(n?)def::(\S+)\[(.*)\]\s*$/) { |
168 | my ($not, $env, $text) = ($1, $2, $3); | |
169 | die "unsuported ifdef usage - implement me" if $text; | |
170 | ||
171 | my $skip = !exists($attributes->{$env}) ? 1 : 0; | |
172 | $skip = ($skip ? 0 : 1 ) if $not; | |
173 | ||
174 | push_environment($env, $skip); | |
175 | next; | |
176 | } elsif ($line =~ m/^endif::(\S+)\[(.*)\]\s*$/) { | |
177 | my ($env, $text) = ($1, $2); | |
178 | die "unsuported ifdef usage - implement me" if $text; | |
179 | pop_environment($env); | |
180 | next; | |
181 | } | |
182 | ||
183 | next if $env_skip; | |
184 | ||
185 | if ($line =~ m/^include::(\S+)(\[.*\]\s*)$/) { | |
186 | my ($fn, $rest) = ($1, $2); | |
187 | print "INCLUDE: $fn\n"; | |
a22a4a80 | 188 | my $new_fn = prepare_adoc_file($target_env, $fn, $attributes); |
c38115e9 DM |
189 | |
190 | print $outfh "include::${new_fn}$rest\n"; | |
191 | next; | |
835dd63b DM |
192 | } |
193 | ||
194 | # fix xrefs | |
a22a4a80 | 195 | $line =~ s/xref:([^\s\[\]]+)\[([^\]]*)\]/replace_xref(${target_env},$1,$2)/ge; |
835dd63b | 196 | |
a22a4a80 | 197 | $line =~ s/<<([^\s,\[\]]+)(?:,(.*?))?>>/replace_xref(${target_env},$1,$2)/ge; |
835dd63b | 198 | |
c38115e9 | 199 | print $outfh $line . "\n"; |
835dd63b DM |
200 | } |
201 | ||
202 | return $outfilename; | |
203 | } | |
204 | ||
a22a4a80 DM |
205 | sub compile_asciidoc { |
206 | my ($env) = @_; | |
835dd63b DM |
207 | |
208 | my $verbose; | |
209 | my $outfile; | |
835dd63b DM |
210 | |
211 | GetOptions ("outfile=s" => \$outfile, | |
212 | "verbose" => \$verbose) or | |
213 | die("Error in command line arguments\n"); | |
214 | ||
215 | my $infile = shift(@ARGV) or | |
216 | die "no input file specified\n"; | |
217 | ||
218 | scalar(@ARGV) == 0 or | |
219 | die "too many arguments...\n"; | |
220 | ||
c38115e9 | 221 | defined($fileinfo->{titles}->{$env}) || |
a22a4a80 | 222 | die "unknown environment '$env'"; |
a22a4a80 | 223 | |
835dd63b | 224 | my $title = $fileinfo->{titles}->{$env}->{$infile} or |
c38115e9 | 225 | die "unable to get title for '$infile'$env\n"; |
835dd63b | 226 | |
835dd63b DM |
227 | print "compile: $title\n"; |
228 | ||
229 | my $leveloffset = 0; | |
230 | ||
c38115e9 DM |
231 | my $doctype = $fileinfo->{doctype}->{$env}->{$infile}; |
232 | ||
233 | die "unable to get document type for '$infile'\n" | |
234 | if !defined($doctype); | |
235 | ||
b489b02c | 236 | $leveloffset = - $doctype; |
835dd63b DM |
237 | |
238 | my $date = `date`; | |
239 | chomp $date; | |
240 | ||
241 | my $attributes = { | |
242 | $env => undef, | |
835dd63b | 243 | leveloffset => $leveloffset, |
835dd63b DM |
244 | }; |
245 | ||
c38115e9 DM |
246 | my $mansection = $fileinfo->{mansection}->{$env}->{$infile}; |
247 | ||
248 | if ($env eq 'wiki') { | |
249 | } elsif ($env eq 'manvolnum') { | |
250 | die "undefined man section" if !defined($mansection); | |
251 | $attributes->{manvolnum} = $mansection; | |
252 | } elsif ($env eq 'default') { | |
253 | die "$infile: wrong doctype\n" if $doctype != 0; | |
a22a4a80 DM |
254 | $attributes->{toc} = undef; |
255 | } | |
256 | ||
c38115e9 DM |
257 | if (!defined($outfile)) { |
258 | $outfile = $infile; | |
259 | $outfile =~ s/\.adoc$//; | |
260 | if ($env eq 'manvolnum') { | |
261 | if ($man_target_html) { | |
262 | $outfile .= ".$mansection.html"; | |
263 | } else { | |
264 | $outfile .= ".$mansection"; | |
265 | } | |
835dd63b | 266 | } else { |
c38115e9 | 267 | $outfile .= ".html"; |
835dd63b DM |
268 | } |
269 | } | |
270 | ||
c38115e9 | 271 | if (($env eq 'manvolnum') && !$man_target_html) { |
835dd63b | 272 | |
c38115e9 DM |
273 | # asciidoc /etc/asciidoc/docbook-xsl/manpage.xsl skip REFERENCES |
274 | # section like footnotes, so we cannot use a2x. | |
275 | # We use xmlto instead. | |
835dd63b | 276 | |
c38115e9 | 277 | my $cmd = ['asciidoc', '-dmanpage', '-bdocbook', '-a', 'docinfo1']; |
835dd63b | 278 | |
c38115e9 DM |
279 | foreach my $key (keys %$attributes) { |
280 | my $value = $attributes->{$key}; | |
281 | if (defined($value)) { | |
282 | push @$cmd, '-a', "$key=$value"; | |
283 | } else { | |
284 | push @$cmd, '-a', $key; | |
285 | } | |
286 | } | |
835dd63b | 287 | |
c38115e9 | 288 | push @$cmd, '--verbose' if $verbose; |
835dd63b | 289 | |
c38115e9 | 290 | my $tmpxmlfile = "${outfile}.xml.tmp"; |
835dd63b | 291 | |
c38115e9 DM |
292 | push @$cmd, '--out-file', $tmpxmlfile; |
293 | ||
294 | my $new_infile = prepare_adoc_file($env, $infile, $attributes); | |
295 | ||
296 | push @$cmd, $new_infile; | |
297 | ||
298 | print "RUN " . join(' ', @$cmd) . "\n"; | |
299 | ||
300 | system(@$cmd) == 0 or | |
301 | die "aciidoc error"; | |
302 | ||
303 | $cmd = ['xmlto', 'man', $tmpxmlfile]; | |
304 | ||
305 | push @$cmd, '-v' if $verbose; | |
306 | ||
307 | print "RUN " . join(' ', @$cmd) . "\n"; | |
308 | ||
309 | system(@$cmd) == 0 or | |
310 | die "xmlto error"; | |
311 | ||
312 | } else { | |
835dd63b | 313 | |
c38115e9 DM |
314 | $attributes->{icons} = undef; |
315 | $attributes->{'data-uri'} = undef; | |
316 | $attributes->{revnumber} = $release; | |
317 | ||
318 | my $cmd = ['asciidoc']; | |
319 | ||
320 | push @$cmd, '-s' if $env eq 'wiki'; | |
321 | ||
322 | foreach my $key (keys %$attributes) { | |
323 | my $value = $attributes->{$key}; | |
324 | if (defined($value)) { | |
325 | push @$cmd, '-a', "$key=$value"; | |
326 | } else { | |
327 | push @$cmd, '-a', $key; | |
328 | } | |
329 | } | |
330 | ||
331 | push @$cmd, '--verbose' if $verbose; | |
332 | ||
333 | push @$cmd, '--out-file', $outfile; | |
334 | ||
335 | my $new_infile = prepare_adoc_file($env, $infile, $attributes); | |
336 | ||
337 | push @$cmd, $new_infile; | |
338 | ||
339 | print "RUN " . join(' ', @$cmd) . "\n"; | |
340 | ||
341 | system(@$cmd) == 0 or | |
342 | die "aciidoc error"; | |
343 | } | |
344 | } | |
a22a4a80 | 345 | |
b489b02c | 346 | if ($clicmd eq 'compile-wiki') { |
835dd63b | 347 | |
a22a4a80 | 348 | eval { compile_asciidoc('wiki'); }; |
835dd63b DM |
349 | my $err = $@; |
350 | ||
17d8be0c | 351 | cleanup(); |
835dd63b DM |
352 | |
353 | die $err if $err; | |
354 | ||
c38115e9 DM |
355 | } elsif ($clicmd eq 'compile-chapter') { |
356 | ||
357 | eval { compile_asciidoc('default'); }; | |
358 | my $err = $@; | |
359 | ||
360 | cleanup(); | |
361 | ||
362 | die $err if $err; | |
363 | ||
364 | } elsif ($clicmd eq 'compile-man-html') { | |
365 | ||
366 | $man_target_html = 1; | |
367 | ||
368 | eval { compile_asciidoc('manvolnum'); }; | |
369 | my $err = $@; | |
370 | ||
371 | cleanup(); | |
372 | ||
373 | die $err if $err; | |
374 | ||
375 | } elsif ($clicmd eq 'compile-man') { | |
376 | ||
377 | eval { compile_asciidoc('manvolnum'); }; | |
378 | my $err = $@; | |
379 | ||
380 | cleanup(); | |
381 | ||
382 | die $err if $err; | |
383 | ||
835dd63b DM |
384 | } else { |
385 | ||
386 | die "unknown command '$clicmd'\n"; | |
387 | ||
388 | } | |
389 | ||
390 | ||
391 | ||
392 | ||
393 | ||
394 | ||
395 | exit 0; | |
aa99b349 DM |
396 | |
397 | __END__ |