blob: c8133b636a41a822938c8c208a48a5c0457940f0 [file] [log] [blame]
Mauro Carvalho Chehab24071ac2017-07-17 18:46:36 -03001#!/usr/bin/perl
Thomas Gleixnerc942fdd2019-05-27 08:55:06 +02002# SPDX-License-Identifier: GPL-2.0-or-later
Mauro Carvalho Chehab24071ac2017-07-17 18:46:36 -03003use strict;
4
5# Copyright (c) 2017 Mauro Carvalho Chehab <mchehab@kernel.org>
6#
Mauro Carvalho Chehab24071ac2017-07-17 18:46:36 -03007
Mauro Carvalho Chehab5be33182017-07-17 18:46:37 -03008my $virtenv_dir = "sphinx_1.4";
Mauro Carvalho Chehabfb947f32017-07-17 18:46:38 -03009my $requirement_file = "Documentation/sphinx/requirements.txt";
Mauro Carvalho Chehab5be33182017-07-17 18:46:37 -030010
Mauro Carvalho Chehab24071ac2017-07-17 18:46:36 -030011#
12# Static vars
13#
14
15my %missing;
16my $system_release;
17my $need = 0;
18my $optional = 0;
19my $need_symlink = 0;
20my $need_sphinx = 0;
21my $install = "";
22
23#
24# Command line arguments
25#
26
27my $pdf = 1;
28my $virtualenv = 1;
29
30#
31# List of required texlive packages on Fedora and OpenSuse
32#
33
34my %texlive = (
Mauro Carvalho Chehab24071ac2017-07-17 18:46:36 -030035 'amsfonts.sty' => 'texlive-amsfonts',
36 'amsmath.sty' => 'texlive-amsmath',
37 'amssymb.sty' => 'texlive-amsfonts',
38 'amsthm.sty' => 'texlive-amscls',
39 'anyfontsize.sty' => 'texlive-anyfontsize',
40 'atbegshi.sty' => 'texlive-oberdiek',
41 'bm.sty' => 'texlive-tools',
42 'capt-of.sty' => 'texlive-capt-of',
43 'cmap.sty' => 'texlive-cmap',
44 'ecrm1000.tfm' => 'texlive-ec',
45 'eqparbox.sty' => 'texlive-eqparbox',
46 'eu1enc.def' => 'texlive-euenc',
47 'fancybox.sty' => 'texlive-fancybox',
48 'fancyvrb.sty' => 'texlive-fancyvrb',
49 'float.sty' => 'texlive-float',
50 'fncychap.sty' => 'texlive-fncychap',
51 'footnote.sty' => 'texlive-mdwtools',
52 'framed.sty' => 'texlive-framed',
53 'luatex85.sty' => 'texlive-luatex85',
54 'multirow.sty' => 'texlive-multirow',
55 'needspace.sty' => 'texlive-needspace',
56 'palatino.sty' => 'texlive-psnfss',
57 'parskip.sty' => 'texlive-parskip',
58 'polyglossia.sty' => 'texlive-polyglossia',
59 'tabulary.sty' => 'texlive-tabulary',
60 'threeparttable.sty' => 'texlive-threeparttable',
61 'titlesec.sty' => 'texlive-titlesec',
62 'ucs.sty' => 'texlive-ucs',
63 'upquote.sty' => 'texlive-upquote',
64 'wrapfig.sty' => 'texlive-wrapfig',
65);
66
67#
68# Subroutines that checks if a feature exists
69#
70
71sub check_missing(%)
72{
73 my %map = %{$_[0]};
74
75 foreach my $prog (sort keys %missing) {
76 my $is_optional = $missing{$prog};
77
78 if ($is_optional) {
79 print "Warning: better to also install \"$prog\".\n";
80 } else {
81 print "ERROR: please install \"$prog\", otherwise, build won't work.\n";
82 }
83 if (defined($map{$prog})) {
84 $install .= " " . $map{$prog};
85 } else {
86 $install .= " " . $prog;
87 }
88 }
89
90 $install =~ s/^\s//;
91}
92
93sub add_package($$)
94{
95 my $package = shift;
96 my $is_optional = shift;
97
98 $missing{$package} = $is_optional;
99 if ($is_optional) {
100 $optional++;
101 } else {
102 $need++;
103 }
104}
105
106sub check_missing_file($$$)
107{
108 my $file = shift;
109 my $package = shift;
110 my $is_optional = shift;
111
112 return if(-e $file);
113
114 add_package($package, $is_optional);
115}
116
117sub findprog($)
118{
119 foreach(split(/:/, $ENV{PATH})) {
120 return "$_/$_[0]" if(-x "$_/$_[0]");
121 }
122}
123
124sub check_program($$)
125{
126 my $prog = shift;
127 my $is_optional = shift;
128
129 return if findprog($prog);
130
131 add_package($prog, $is_optional);
132}
133
134sub check_perl_module($$)
135{
136 my $prog = shift;
137 my $is_optional = shift;
138
139 my $err = system("perl -M$prog -e 1 2>/dev/null /dev/null");
140 return if ($err == 0);
141
142 add_package($prog, $is_optional);
143}
144
145sub check_python_module($$)
146{
147 my $prog = shift;
148 my $is_optional = shift;
149
150 my $err = system("python3 -c 'import $prog' 2>/dev/null /dev/null");
151 return if ($err == 0);
152 my $err = system("python -c 'import $prog' 2>/dev/null /dev/null");
153 return if ($err == 0);
154
155 add_package($prog, $is_optional);
156}
157
158sub check_rpm_missing($$)
159{
160 my @pkgs = @{$_[0]};
161 my $is_optional = $_[1];
162
163 foreach my $prog(@pkgs) {
164 my $err = system("rpm -q '$prog' 2>/dev/null >/dev/null");
165 add_package($prog, $is_optional) if ($err);
166 }
167}
168
169sub check_pacman_missing($$)
170{
171 my @pkgs = @{$_[0]};
172 my $is_optional = $_[1];
173
174 foreach my $prog(@pkgs) {
175 my $err = system("pacman -Q '$prog' 2>/dev/null >/dev/null");
176 add_package($prog, $is_optional) if ($err);
177 }
178}
179
180sub check_missing_tex($)
181{
182 my $is_optional = shift;
183 my $kpsewhich = findprog("kpsewhich");
184
185 foreach my $prog(keys %texlive) {
186 my $package = $texlive{$prog};
187 if (!$kpsewhich) {
188 add_package($package, $is_optional);
189 next;
190 }
191 my $file = qx($kpsewhich $prog);
192 add_package($package, $is_optional) if ($file =~ /^\s*$/);
193 }
194}
195
196sub check_sphinx()
197{
198 return if findprog("sphinx-build");
199
200 if (findprog("sphinx-build-3")) {
201 $need_symlink = 1;
202 return;
203 }
204
205 if ($virtualenv) {
Mauro Carvalho Chehab800d4082017-07-21 13:20:41 -0300206 my $prog = findprog("virtualenv-3");
207 $prog = findprog("virtualenv-3.5") if (!$prog);
208
209 check_program("virtualenv", 0) if (!$prog);
Mauro Carvalho Chehab24071ac2017-07-17 18:46:36 -0300210 $need_sphinx = 1;
211 } else {
212 add_package("python-sphinx", 0);
213 }
214}
215
216#
217# Ancillary subroutines
218#
219
220sub catcheck($)
221{
222 my $res = "";
223 $res = qx(cat $_[0]) if (-r $_[0]);
224 return $res;
225}
226
227sub which($)
228{
229 my $file = shift;
230 my @path = split ":", $ENV{PATH};
231
232 foreach my $dir(@path) {
233 my $name = $dir.'/'.$file;
234 return $name if (-x $name );
235 }
236 return undef;
237}
238
239#
240# Subroutines that check distro-specific hints
241#
242
243sub give_debian_hints()
244{
245 my %map = (
246 "python-sphinx" => "python3-sphinx",
247 "sphinx_rtd_theme" => "python3-sphinx-rtd-theme",
248 "virtualenv" => "virtualenv",
Mauro Carvalho Chehab24071ac2017-07-17 18:46:36 -0300249 "dot" => "graphviz",
250 "convert" => "imagemagick",
251 "Pod::Usage" => "perl-modules",
252 "xelatex" => "texlive-xetex",
Mauro Carvalho Chehab8e7d5d12017-07-17 18:46:40 -0300253 "rsvg-convert" => "librsvg2-bin",
Mauro Carvalho Chehab24071ac2017-07-17 18:46:36 -0300254 );
255
256 if ($pdf) {
257 check_missing_file("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
258 "fonts-dejavu", 1);
259 }
260
261 check_program("dvipng", 1) if ($pdf);
262 check_missing(\%map);
263
264 return if (!$need && !$optional);
265 printf("You should run:\n\n\tsudo apt-get install $install\n");
266}
267
268sub give_redhat_hints()
269{
270 my %map = (
271 "python-sphinx" => "python3-sphinx",
272 "sphinx_rtd_theme" => "python3-sphinx_rtd_theme",
273 "virtualenv" => "python3-virtualenv",
Mauro Carvalho Chehab24071ac2017-07-17 18:46:36 -0300274 "dot" => "graphviz",
275 "convert" => "ImageMagick",
276 "Pod::Usage" => "perl-Pod-Usage",
277 "xelatex" => "texlive-xetex-bin",
Mauro Carvalho Chehab8e7d5d12017-07-17 18:46:40 -0300278 "rsvg-convert" => "librsvg2-tools",
Mauro Carvalho Chehab24071ac2017-07-17 18:46:36 -0300279 );
280
Mauro Carvalho Chehab5d889532017-07-17 18:46:39 -0300281 my @fedora26_opt_pkgs = (
282 "graphviz-gd", # Fedora 26: needed for PDF support
283 );
284
Mauro Carvalho Chehab24071ac2017-07-17 18:46:36 -0300285 my @fedora_tex_pkgs = (
286 "texlive-collection-fontsrecommended",
287 "texlive-collection-latex",
288 "dejavu-sans-fonts",
289 "dejavu-serif-fonts",
290 "dejavu-sans-mono-fonts",
291 );
292
Mauro Carvalho Chehab9b756a92017-07-24 09:09:24 -0300293 #
294 # Checks valid for RHEL/CentOS version 7.x.
295 #
296 if (! $system_release =~ /Fedora/) {
297 $map{"virtualenv"} = "python-virtualenv";
298 }
299
Mauro Carvalho Chehab5d889532017-07-17 18:46:39 -0300300 my $release;
301
302 $release = $1 if ($system_release =~ /Fedora\s+release\s+(\d+)/);
303
304 check_rpm_missing(\@fedora26_opt_pkgs, 1) if ($pdf && $release >= 26);
Mauro Carvalho Chehab24071ac2017-07-17 18:46:36 -0300305 check_rpm_missing(\@fedora_tex_pkgs, 1) if ($pdf);
306 check_missing_tex(1) if ($pdf);
307 check_missing(\%map);
308
309 return if (!$need && !$optional);
Mauro Carvalho Chehab9b756a92017-07-24 09:09:24 -0300310
311 if ($release >= 18) {
312 # dnf, for Fedora 18+
313 printf("You should run:\n\n\tsudo dnf install -y $install\n");
314 } else {
315 # yum, for RHEL (and clones) or Fedora version < 18
316 printf("You should run:\n\n\tsudo yum install -y $install\n");
317 }
Mauro Carvalho Chehab24071ac2017-07-17 18:46:36 -0300318}
319
320sub give_opensuse_hints()
321{
322 my %map = (
323 "python-sphinx" => "python3-sphinx",
324 "sphinx_rtd_theme" => "python3-sphinx_rtd_theme",
325 "virtualenv" => "python3-virtualenv",
Mauro Carvalho Chehab24071ac2017-07-17 18:46:36 -0300326 "dot" => "graphviz",
327 "convert" => "ImageMagick",
328 "Pod::Usage" => "perl-Pod-Usage",
329 "xelatex" => "texlive-xetex-bin",
Mauro Carvalho Chehab8e7d5d12017-07-17 18:46:40 -0300330 "rsvg-convert" => "rsvg-view",
Mauro Carvalho Chehab24071ac2017-07-17 18:46:36 -0300331 );
332
333 my @suse_tex_pkgs = (
334 "texlive-babel-english",
335 "texlive-caption",
336 "texlive-colortbl",
337 "texlive-courier",
338 "texlive-dvips",
339 "texlive-helvetic",
340 "texlive-makeindex",
341 "texlive-metafont",
342 "texlive-metapost",
343 "texlive-palatino",
344 "texlive-preview",
345 "texlive-times",
346 "texlive-zapfchan",
347 "texlive-zapfding",
348 );
349
350 check_rpm_missing(\@suse_tex_pkgs, 1) if ($pdf);
351 check_missing_tex(1) if ($pdf);
352 check_missing(\%map);
353
354 return if (!$need && !$optional);
355 printf("You should run:\n\n\tsudo zypper install --no-recommends $install\n");
356}
357
Mauro Carvalho Chehab800d4082017-07-21 13:20:41 -0300358sub give_mageia_hints()
359{
360 my %map = (
361 "python-sphinx" => "python3-sphinx",
362 "sphinx_rtd_theme" => "python3-sphinx_rtd_theme",
363 "virtualenv" => "python3-virtualenv",
Mauro Carvalho Chehab800d4082017-07-21 13:20:41 -0300364 "dot" => "graphviz",
365 "convert" => "ImageMagick",
366 "Pod::Usage" => "perl-Pod-Usage",
367 "xelatex" => "texlive",
368 "rsvg-convert" => "librsvg2-tools",
369 );
370
371 my @tex_pkgs = (
372 "texlive-fontsextra",
373 );
374
Mauro Carvalho Chehab800d4082017-07-21 13:20:41 -0300375 check_rpm_missing(\@tex_pkgs, 1) if ($pdf);
376 check_missing(\%map);
377
378 return if (!$need && !$optional);
379 printf("You should run:\n\n\tsudo urpmi $install\n");
380}
381
Mauro Carvalho Chehab24071ac2017-07-17 18:46:36 -0300382sub give_arch_linux_hints()
383{
384 my %map = (
385 "sphinx_rtd_theme" => "python-sphinx_rtd_theme",
386 "virtualenv" => "python-virtualenv",
Mauro Carvalho Chehab24071ac2017-07-17 18:46:36 -0300387 "dot" => "graphviz",
388 "convert" => "imagemagick",
389 "xelatex" => "texlive-bin",
Mauro Carvalho Chehab8e7d5d12017-07-17 18:46:40 -0300390 "rsvg-convert" => "extra/librsvg",
Mauro Carvalho Chehab24071ac2017-07-17 18:46:36 -0300391 );
392
393 my @archlinux_tex_pkgs = (
394 "texlive-core",
395 "texlive-latexextra",
396 "ttf-dejavu",
397 );
398 check_pacman_missing(\@archlinux_tex_pkgs, 1) if ($pdf);
399 check_missing(\%map);
400
401 return if (!$need && !$optional);
402 printf("You should run:\n\n\tsudo pacman -S $install\n");
403}
404
405sub give_gentoo_hints()
406{
407 my %map = (
408 "sphinx_rtd_theme" => "dev-python/sphinx_rtd_theme",
409 "virtualenv" => "dev-python/virtualenv",
Mauro Carvalho Chehab24071ac2017-07-17 18:46:36 -0300410 "dot" => "media-gfx/graphviz",
411 "convert" => "media-gfx/imagemagick",
412 "xelatex" => "dev-texlive/texlive-xetex media-fonts/dejavu",
Mauro Carvalho Chehab8e7d5d12017-07-17 18:46:40 -0300413 "rsvg-convert" => "gnome-base/librsvg",
Mauro Carvalho Chehab24071ac2017-07-17 18:46:36 -0300414 );
415
416 check_missing_file("/usr/share/fonts/dejavu/DejaVuSans.ttf",
417 "media-fonts/dejavu", 1) if ($pdf);
418
419 check_missing(\%map);
420
421 return if (!$need && !$optional);
Mauro Carvalho Chehabbba1e4c2017-07-17 18:46:41 -0300422
423 printf("You should run:\n\n");
424 printf("\tsudo su -c 'echo \"media-gfx/imagemagick svg png\" > /etc/portage/package.use/imagemagick'\n");
425 printf("\tsudo su -c 'echo \"media-gfx/graphviz cairo pdf\" > /etc/portage/package.use/graphviz'\n");
426 printf("\tsudo emerge --ask $install\n");
427
Mauro Carvalho Chehab24071ac2017-07-17 18:46:36 -0300428}
429
430sub check_distros()
431{
432 # Distro-specific hints
433 if ($system_release =~ /Red Hat Enterprise Linux/) {
434 give_redhat_hints;
435 return;
436 }
Mauro Carvalho Chehab9b756a92017-07-24 09:09:24 -0300437 if ($system_release =~ /CentOS/) {
438 give_redhat_hints;
439 return;
440 }
441 if ($system_release =~ /Scientific Linux/) {
442 give_redhat_hints;
443 return;
444 }
445 if ($system_release =~ /Oracle Linux Server/) {
446 give_redhat_hints;
447 return;
448 }
Mauro Carvalho Chehab24071ac2017-07-17 18:46:36 -0300449 if ($system_release =~ /Fedora/) {
450 give_redhat_hints;
451 return;
452 }
453 if ($system_release =~ /Ubuntu/) {
454 give_debian_hints;
455 return;
456 }
457 if ($system_release =~ /Debian/) {
458 give_debian_hints;
459 return;
460 }
461 if ($system_release =~ /openSUSE/) {
462 give_opensuse_hints;
463 return;
464 }
Mauro Carvalho Chehab800d4082017-07-21 13:20:41 -0300465 if ($system_release =~ /Mageia/) {
466 give_mageia_hints;
467 return;
468 }
Mauro Carvalho Chehab24071ac2017-07-17 18:46:36 -0300469 if ($system_release =~ /Arch Linux/) {
470 give_arch_linux_hints;
471 return;
472 }
473 if ($system_release =~ /Gentoo/) {
474 give_gentoo_hints;
475 return;
476 }
477
478 #
479 # Fall-back to generic hint code for other distros
480 # That's far from ideal, specially for LaTeX dependencies.
481 #
482 my %map = (
483 "sphinx-build" => "sphinx"
484 );
485 check_missing_tex(1) if ($pdf);
486 check_missing(\%map);
487 print "I don't know distro $system_release.\n";
488 print "So, I can't provide you a hint with the install procedure.\n";
489 print "There are likely missing dependencies.\n";
490}
491
492#
493# Common dependencies
494#
495
496sub check_needs()
497{
498 if ($system_release) {
Mauro Carvalho Chehab9b756a92017-07-24 09:09:24 -0300499 print "Detected OS: $system_release.\n";
Mauro Carvalho Chehab24071ac2017-07-17 18:46:36 -0300500 } else {
Mauro Carvalho Chehab9b756a92017-07-24 09:09:24 -0300501 print "Unknown OS\n";
502 }
503
504 # RHEL 7.x and clones have Sphinx version 1.1.x and incomplete texlive
505 if (($system_release =~ /Red Hat Enterprise Linux/) ||
506 ($system_release =~ /CentOS/) ||
507 ($system_release =~ /Scientific Linux/) ||
508 ($system_release =~ /Oracle Linux Server/)) {
509 $virtualenv = 1;
510 $pdf = 0;
511
512 printf("NOTE: On this distro, Sphinx and TexLive shipped versions are incompatible\n");
513 printf("with doc build. So, use Sphinx via a Python virtual environment.\n\n");
514 printf("This script can't install a TexLive version that would provide PDF.\n");
Mauro Carvalho Chehab24071ac2017-07-17 18:46:36 -0300515 }
516
517 # Check for needed programs/tools
518 check_sphinx();
519 check_perl_module("Pod::Usage", 0);
520 check_program("make", 0);
521 check_program("gcc", 0);
522 check_python_module("sphinx_rtd_theme", 1) if (!$virtualenv);
523 check_program("xelatex", 1) if ($pdf);
524 check_program("dot", 1);
525 check_program("convert", 1);
Mauro Carvalho Chehab8e7d5d12017-07-17 18:46:40 -0300526 check_program("rsvg-convert", 1) if ($pdf);
Mauro Carvalho Chehab5f6df002019-03-30 10:45:59 -0300527 check_program("latexmk", 1) if ($pdf);
Mauro Carvalho Chehab24071ac2017-07-17 18:46:36 -0300528
529 check_distros();
530
531 if ($need_symlink) {
532 printf "\tsudo ln -sf %s /usr/bin/sphinx-build\n\n",
533 which("sphinx-build-3");
534 }
535 if ($need_sphinx) {
Mauro Carvalho Chehab5be33182017-07-17 18:46:37 -0300536 my $activate = "$virtenv_dir/bin/activate";
537 if (-e "$ENV{'PWD'}/$activate") {
538 printf "\nNeed to activate virtualenv with:\n";
539 printf "\t. $activate\n";
540 } else {
541 my $virtualenv = findprog("virtualenv-3");
Mauro Carvalho Chehab800d4082017-07-21 13:20:41 -0300542 $virtualenv = findprog("virtualenv-3.5") if (!$virtualenv);
Mauro Carvalho Chehab5be33182017-07-17 18:46:37 -0300543 $virtualenv = findprog("virtualenv") if (!$virtualenv);
544 $virtualenv = "virtualenv" if (!$virtualenv);
Mauro Carvalho Chehab24071ac2017-07-17 18:46:36 -0300545
Mauro Carvalho Chehab5be33182017-07-17 18:46:37 -0300546 printf "\t$virtualenv $virtenv_dir\n";
547 printf "\t. $activate\n";
Mauro Carvalho Chehabfb947f32017-07-17 18:46:38 -0300548 printf "\tpip install -r $requirement_file\n";
Mauro Carvalho Chehab5be33182017-07-17 18:46:37 -0300549 $need++;
550 }
Mauro Carvalho Chehab24071ac2017-07-17 18:46:36 -0300551 }
552 printf "\n";
553
554 print "All optional dependenties are met.\n" if (!$optional);
555
556 if ($need == 1) {
557 die "Can't build as $need mandatory dependency is missing";
558 } elsif ($need) {
559 die "Can't build as $need mandatory dependencies are missing";
560 }
561
562 print "Needed package dependencies are met.\n";
563}
564
565#
566# Main
567#
568
569while (@ARGV) {
570 my $arg = shift(@ARGV);
571
572 if ($arg eq "--no-virtualenv") {
573 $virtualenv = 0;
574 } elsif ($arg eq "--no-pdf"){
575 $pdf = 0;
576 } else {
577 print "Usage:\n\t$0 <--no-virtualenv> <--no-pdf>\n\n";
578 exit -1;
579 }
580}
581
582#
583# Determine the system type. There's no standard unique way that would
584# work with all distros with a minimal package install. So, several
585# methods are used here.
586#
587# By default, it will use lsb_release function. If not available, it will
588# fail back to reading the known different places where the distro name
589# is stored
590#
591
592$system_release = qx(lsb_release -d) if which("lsb_release");
593$system_release =~ s/Description:\s*// if ($system_release);
594$system_release = catcheck("/etc/system-release") if !$system_release;
595$system_release = catcheck("/etc/redhat-release") if !$system_release;
596$system_release = catcheck("/etc/lsb-release") if !$system_release;
597$system_release = catcheck("/etc/gentoo-release") if !$system_release;
598$system_release = catcheck("/etc/issue") if !$system_release;
599$system_release =~ s/\s+$//;
600
601check_needs;