sphinx-pre-install 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925
  1. #!/usr/bin/env perl
  2. # SPDX-License-Identifier: GPL-2.0-or-later
  3. use strict;
  4. # Copyright (c) 2017-2020 Mauro Carvalho Chehab <mchehab@kernel.org>
  5. #
  6. my $prefix = "./";
  7. $prefix = "$ENV{'srctree'}/" if ($ENV{'srctree'});
  8. my $conf = $prefix . "Documentation/conf.py";
  9. my $requirement_file = $prefix . "Documentation/sphinx/requirements.txt";
  10. my $virtenv_prefix = "sphinx_";
  11. #
  12. # Static vars
  13. #
  14. my %missing;
  15. my $system_release;
  16. my $need = 0;
  17. my $optional = 0;
  18. my $need_symlink = 0;
  19. my $need_sphinx = 0;
  20. my $need_venv = 0;
  21. my $need_virtualenv = 0;
  22. my $rec_sphinx_upgrade = 0;
  23. my $install = "";
  24. my $virtenv_dir = "";
  25. my $python_cmd = "";
  26. my $min_version;
  27. my $cur_version;
  28. my $rec_version = "1.7.9"; # PDF won't build here
  29. my $min_pdf_version = "2.4.4"; # Min version where pdf builds
  30. #
  31. # Command line arguments
  32. #
  33. my $pdf = 1;
  34. my $virtualenv = 1;
  35. my $version_check = 0;
  36. #
  37. # List of required texlive packages on Fedora and OpenSuse
  38. #
  39. my %texlive = (
  40. 'amsfonts.sty' => 'texlive-amsfonts',
  41. 'amsmath.sty' => 'texlive-amsmath',
  42. 'amssymb.sty' => 'texlive-amsfonts',
  43. 'amsthm.sty' => 'texlive-amscls',
  44. 'anyfontsize.sty' => 'texlive-anyfontsize',
  45. 'atbegshi.sty' => 'texlive-oberdiek',
  46. 'bm.sty' => 'texlive-tools',
  47. 'capt-of.sty' => 'texlive-capt-of',
  48. 'cmap.sty' => 'texlive-cmap',
  49. 'ecrm1000.tfm' => 'texlive-ec',
  50. 'eqparbox.sty' => 'texlive-eqparbox',
  51. 'eu1enc.def' => 'texlive-euenc',
  52. 'fancybox.sty' => 'texlive-fancybox',
  53. 'fancyvrb.sty' => 'texlive-fancyvrb',
  54. 'float.sty' => 'texlive-float',
  55. 'fncychap.sty' => 'texlive-fncychap',
  56. 'footnote.sty' => 'texlive-mdwtools',
  57. 'framed.sty' => 'texlive-framed',
  58. 'luatex85.sty' => 'texlive-luatex85',
  59. 'multirow.sty' => 'texlive-multirow',
  60. 'needspace.sty' => 'texlive-needspace',
  61. 'palatino.sty' => 'texlive-psnfss',
  62. 'parskip.sty' => 'texlive-parskip',
  63. 'polyglossia.sty' => 'texlive-polyglossia',
  64. 'tabulary.sty' => 'texlive-tabulary',
  65. 'threeparttable.sty' => 'texlive-threeparttable',
  66. 'titlesec.sty' => 'texlive-titlesec',
  67. 'ucs.sty' => 'texlive-ucs',
  68. 'upquote.sty' => 'texlive-upquote',
  69. 'wrapfig.sty' => 'texlive-wrapfig',
  70. 'ctexhook.sty' => 'texlive-ctex',
  71. );
  72. #
  73. # Subroutines that checks if a feature exists
  74. #
  75. sub check_missing(%)
  76. {
  77. my %map = %{$_[0]};
  78. foreach my $prog (sort keys %missing) {
  79. my $is_optional = $missing{$prog};
  80. # At least on some LTS distros like CentOS 7, texlive doesn't
  81. # provide all packages we need. When such distros are
  82. # detected, we have to disable PDF output.
  83. #
  84. # So, we need to ignore the packages that distros would
  85. # need for LaTeX to work
  86. if ($is_optional == 2 && !$pdf) {
  87. $optional--;
  88. next;
  89. }
  90. if ($is_optional) {
  91. print "Warning: better to also install \"$prog\".\n";
  92. } else {
  93. print "ERROR: please install \"$prog\", otherwise, build won't work.\n";
  94. }
  95. if (defined($map{$prog})) {
  96. $install .= " " . $map{$prog};
  97. } else {
  98. $install .= " " . $prog;
  99. }
  100. }
  101. $install =~ s/^\s//;
  102. }
  103. sub add_package($$)
  104. {
  105. my $package = shift;
  106. my $is_optional = shift;
  107. $missing{$package} = $is_optional;
  108. if ($is_optional) {
  109. $optional++;
  110. } else {
  111. $need++;
  112. }
  113. }
  114. sub check_missing_file($$$)
  115. {
  116. my $files = shift;
  117. my $package = shift;
  118. my $is_optional = shift;
  119. for (@$files) {
  120. return if(-e $_);
  121. }
  122. add_package($package, $is_optional);
  123. }
  124. sub findprog($)
  125. {
  126. foreach(split(/:/, $ENV{PATH})) {
  127. return "$_/$_[0]" if(-x "$_/$_[0]");
  128. }
  129. }
  130. sub find_python_no_venv()
  131. {
  132. my $prog = shift;
  133. my $cur_dir = qx(pwd);
  134. $cur_dir =~ s/\s+$//;
  135. foreach my $dir (split(/:/, $ENV{PATH})) {
  136. next if ($dir =~ m,($cur_dir)/sphinx,);
  137. return "$dir/python3" if(-x "$dir/python3");
  138. }
  139. foreach my $dir (split(/:/, $ENV{PATH})) {
  140. next if ($dir =~ m,($cur_dir)/sphinx,);
  141. return "$dir/python" if(-x "$dir/python");
  142. }
  143. return "python";
  144. }
  145. sub check_program($$)
  146. {
  147. my $prog = shift;
  148. my $is_optional = shift;
  149. return $prog if findprog($prog);
  150. add_package($prog, $is_optional);
  151. }
  152. sub check_perl_module($$)
  153. {
  154. my $prog = shift;
  155. my $is_optional = shift;
  156. my $err = system("perl -M$prog -e 1 2>/dev/null /dev/null");
  157. return if ($err == 0);
  158. add_package($prog, $is_optional);
  159. }
  160. sub check_python_module($$)
  161. {
  162. my $prog = shift;
  163. my $is_optional = shift;
  164. return if (!$python_cmd);
  165. my $err = system("$python_cmd -c 'import $prog' 2>/dev/null /dev/null");
  166. return if ($err == 0);
  167. add_package($prog, $is_optional);
  168. }
  169. sub check_rpm_missing($$)
  170. {
  171. my @pkgs = @{$_[0]};
  172. my $is_optional = $_[1];
  173. foreach my $prog(@pkgs) {
  174. my $err = system("rpm -q '$prog' 2>/dev/null >/dev/null");
  175. add_package($prog, $is_optional) if ($err);
  176. }
  177. }
  178. sub check_pacman_missing($$)
  179. {
  180. my @pkgs = @{$_[0]};
  181. my $is_optional = $_[1];
  182. foreach my $prog(@pkgs) {
  183. my $err = system("pacman -Q '$prog' 2>/dev/null >/dev/null");
  184. add_package($prog, $is_optional) if ($err);
  185. }
  186. }
  187. sub check_missing_tex($)
  188. {
  189. my $is_optional = shift;
  190. my $kpsewhich = findprog("kpsewhich");
  191. foreach my $prog(keys %texlive) {
  192. my $package = $texlive{$prog};
  193. if (!$kpsewhich) {
  194. add_package($package, $is_optional);
  195. next;
  196. }
  197. my $file = qx($kpsewhich $prog);
  198. add_package($package, $is_optional) if ($file =~ /^\s*$/);
  199. }
  200. }
  201. sub get_sphinx_fname()
  202. {
  203. my $fname = "sphinx-build";
  204. return $fname if findprog($fname);
  205. $fname = "sphinx-build-3";
  206. if (findprog($fname)) {
  207. $need_symlink = 1;
  208. return $fname;
  209. }
  210. return "";
  211. }
  212. sub get_sphinx_version($)
  213. {
  214. my $cmd = shift;
  215. my $ver;
  216. open IN, "$cmd --version 2>&1 |";
  217. while (<IN>) {
  218. if (m/^\s*sphinx-build\s+([\d\.]+)(\+\/[\da-f]+)?$/) {
  219. $ver=$1;
  220. last;
  221. }
  222. # Sphinx 1.2.x uses a different format
  223. if (m/^\s*Sphinx.*\s+([\d\.]+)$/) {
  224. $ver=$1;
  225. last;
  226. }
  227. }
  228. close IN;
  229. return $ver;
  230. }
  231. sub check_sphinx()
  232. {
  233. my $default_version;
  234. open IN, $conf or die "Can't open $conf";
  235. while (<IN>) {
  236. if (m/^\s*needs_sphinx\s*=\s*[\'\"]([\d\.]+)[\'\"]/) {
  237. $min_version=$1;
  238. last;
  239. }
  240. }
  241. close IN;
  242. die "Can't get needs_sphinx version from $conf" if (!$min_version);
  243. open IN, $requirement_file or die "Can't open $requirement_file";
  244. while (<IN>) {
  245. if (m/^\s*Sphinx\s*==\s*([\d\.]+)$/) {
  246. $default_version=$1;
  247. last;
  248. }
  249. }
  250. close IN;
  251. die "Can't get default sphinx version from $requirement_file" if (!$default_version);
  252. $virtenv_dir = $virtenv_prefix . $default_version;
  253. my $sphinx = get_sphinx_fname();
  254. if ($sphinx eq "") {
  255. $need_sphinx = 1;
  256. return;
  257. }
  258. $cur_version = get_sphinx_version($sphinx);
  259. die ("$sphinx returned an error") if (!$cur_version);
  260. die "$sphinx didn't return its version" if (!$cur_version);
  261. if ($cur_version lt $min_version) {
  262. printf "ERROR: Sphinx version is %s. It should be >= %s (recommended >= %s)\n",
  263. $cur_version, $min_version, $default_version;
  264. $need_sphinx = 1;
  265. return;
  266. }
  267. if ($cur_version lt $rec_version) {
  268. $rec_sphinx_upgrade = 1;
  269. return;
  270. }
  271. # On version check mode, just assume Sphinx has all mandatory deps
  272. exit (0) if ($version_check);
  273. }
  274. #
  275. # Ancillary subroutines
  276. #
  277. sub catcheck($)
  278. {
  279. my $res = "";
  280. $res = qx(cat $_[0]) if (-r $_[0]);
  281. return $res;
  282. }
  283. sub which($)
  284. {
  285. my $file = shift;
  286. my @path = split ":", $ENV{PATH};
  287. foreach my $dir(@path) {
  288. my $name = $dir.'/'.$file;
  289. return $name if (-x $name );
  290. }
  291. return undef;
  292. }
  293. #
  294. # Subroutines that check distro-specific hints
  295. #
  296. sub give_debian_hints()
  297. {
  298. my %map = (
  299. "python-sphinx" => "python3-sphinx",
  300. "sphinx_rtd_theme" => "python3-sphinx-rtd-theme",
  301. "ensurepip" => "python3-venv",
  302. "virtualenv" => "virtualenv",
  303. "dot" => "graphviz",
  304. "convert" => "imagemagick",
  305. "Pod::Usage" => "perl-modules",
  306. "xelatex" => "texlive-xetex",
  307. "rsvg-convert" => "librsvg2-bin",
  308. );
  309. if ($pdf) {
  310. check_missing_file(["/usr/share/texlive/texmf-dist/tex/latex/ctex/ctexhook.sty"],
  311. "texlive-lang-chinese", 2);
  312. check_missing_file(["/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"],
  313. "fonts-dejavu", 2);
  314. check_missing_file(["/usr/share/fonts/noto-cjk/NotoSansCJK-Regular.ttc",
  315. "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc",
  316. "/usr/share/fonts/opentype/noto/NotoSerifCJK-Regular.ttc"],
  317. "fonts-noto-cjk", 2);
  318. }
  319. check_program("dvipng", 2) if ($pdf);
  320. check_missing(\%map);
  321. return if (!$need && !$optional);
  322. printf("You should run:\n\n\tsudo apt-get install $install\n");
  323. }
  324. sub give_redhat_hints()
  325. {
  326. my %map = (
  327. "python-sphinx" => "python3-sphinx",
  328. "sphinx_rtd_theme" => "python3-sphinx_rtd_theme",
  329. "virtualenv" => "python3-virtualenv",
  330. "dot" => "graphviz",
  331. "convert" => "ImageMagick",
  332. "Pod::Usage" => "perl-Pod-Usage",
  333. "xelatex" => "texlive-xetex-bin",
  334. "rsvg-convert" => "librsvg2-tools",
  335. );
  336. my @fedora26_opt_pkgs = (
  337. "graphviz-gd", # Fedora 26: needed for PDF support
  338. );
  339. my @fedora_tex_pkgs = (
  340. "texlive-collection-fontsrecommended",
  341. "texlive-collection-latex",
  342. "texlive-xecjk",
  343. "dejavu-sans-fonts",
  344. "dejavu-serif-fonts",
  345. "dejavu-sans-mono-fonts",
  346. );
  347. #
  348. # Checks valid for RHEL/CentOS version 7.x.
  349. #
  350. my $old = 0;
  351. my $rel;
  352. $rel = $1 if ($system_release =~ /release\s+(\d+)/);
  353. if (!($system_release =~ /Fedora/)) {
  354. $map{"virtualenv"} = "python-virtualenv";
  355. if ($rel && $rel < 8) {
  356. $old = 1;
  357. $pdf = 0;
  358. printf("Note: texlive packages on RHEL/CENTOS <= 7 are incomplete. Can't support PDF output\n");
  359. printf("If you want to build PDF, please read:\n");
  360. printf("\thttps://www.systutorials.com/241660/how-to-install-tex-live-on-centos-7-linux/\n");
  361. }
  362. } else {
  363. if ($rel && $rel < 26) {
  364. $old = 1;
  365. }
  366. }
  367. if (!$rel) {
  368. printf("Couldn't identify release number\n");
  369. $old = 1;
  370. $pdf = 0;
  371. }
  372. if ($pdf) {
  373. check_missing_file(["/usr/share/fonts/google-noto-cjk/NotoSansCJK-Regular.ttc"],
  374. "google-noto-sans-cjk-ttc-fonts", 2);
  375. }
  376. check_rpm_missing(\@fedora26_opt_pkgs, 2) if ($pdf && !$old);
  377. check_rpm_missing(\@fedora_tex_pkgs, 2) if ($pdf);
  378. check_missing_tex(2) if ($pdf);
  379. check_missing(\%map);
  380. return if (!$need && !$optional);
  381. if (!$old) {
  382. # dnf, for Fedora 18+
  383. printf("You should run:\n\n\tsudo dnf install -y $install\n");
  384. } else {
  385. # yum, for RHEL (and clones) or Fedora version < 18
  386. printf("You should run:\n\n\tsudo yum install -y $install\n");
  387. }
  388. }
  389. sub give_opensuse_hints()
  390. {
  391. my %map = (
  392. "python-sphinx" => "python3-sphinx",
  393. "sphinx_rtd_theme" => "python3-sphinx_rtd_theme",
  394. "virtualenv" => "python3-virtualenv",
  395. "dot" => "graphviz",
  396. "convert" => "ImageMagick",
  397. "Pod::Usage" => "perl-Pod-Usage",
  398. "xelatex" => "texlive-xetex-bin",
  399. );
  400. # On Tumbleweed, this package is also named rsvg-convert
  401. $map{"rsvg-convert"} = "rsvg-view" if (!($system_release =~ /Tumbleweed/));
  402. my @suse_tex_pkgs = (
  403. "texlive-babel-english",
  404. "texlive-caption",
  405. "texlive-colortbl",
  406. "texlive-courier",
  407. "texlive-dvips",
  408. "texlive-helvetic",
  409. "texlive-makeindex",
  410. "texlive-metafont",
  411. "texlive-metapost",
  412. "texlive-palatino",
  413. "texlive-preview",
  414. "texlive-times",
  415. "texlive-zapfchan",
  416. "texlive-zapfding",
  417. );
  418. $map{"latexmk"} = "texlive-latexmk-bin";
  419. # FIXME: add support for installing CJK fonts
  420. #
  421. # I tried hard, but was unable to find a way to install
  422. # "Noto Sans CJK SC" on openSUSE
  423. check_rpm_missing(\@suse_tex_pkgs, 2) if ($pdf);
  424. check_missing_tex(2) if ($pdf);
  425. check_missing(\%map);
  426. return if (!$need && !$optional);
  427. printf("You should run:\n\n\tsudo zypper install --no-recommends $install\n");
  428. }
  429. sub give_mageia_hints()
  430. {
  431. my %map = (
  432. "python-sphinx" => "python3-sphinx",
  433. "sphinx_rtd_theme" => "python3-sphinx_rtd_theme",
  434. "virtualenv" => "python3-virtualenv",
  435. "dot" => "graphviz",
  436. "convert" => "ImageMagick",
  437. "Pod::Usage" => "perl-Pod-Usage",
  438. "xelatex" => "texlive",
  439. "rsvg-convert" => "librsvg2",
  440. );
  441. my @tex_pkgs = (
  442. "texlive-fontsextra",
  443. );
  444. $map{"latexmk"} = "texlive-collection-basic";
  445. my $packager_cmd;
  446. my $noto_sans;
  447. if ($system_release =~ /OpenMandriva/) {
  448. $packager_cmd = "dnf install";
  449. $noto_sans = "noto-sans-cjk-fonts";
  450. @tex_pkgs = ( "texlive-collection-fontsextra" );
  451. } else {
  452. $packager_cmd = "urpmi";
  453. $noto_sans = "google-noto-sans-cjk-ttc-fonts";
  454. }
  455. if ($pdf) {
  456. check_missing_file(["/usr/share/fonts/google-noto-cjk/NotoSansCJK-Regular.ttc",
  457. "/usr/share/fonts/TTF/NotoSans-Regular.ttf"],
  458. $noto_sans, 2);
  459. }
  460. check_rpm_missing(\@tex_pkgs, 2) if ($pdf);
  461. check_missing(\%map);
  462. return if (!$need && !$optional);
  463. printf("You should run:\n\n\tsudo $packager_cmd $install\n");
  464. }
  465. sub give_arch_linux_hints()
  466. {
  467. my %map = (
  468. "sphinx_rtd_theme" => "python-sphinx_rtd_theme",
  469. "virtualenv" => "python-virtualenv",
  470. "dot" => "graphviz",
  471. "convert" => "imagemagick",
  472. "xelatex" => "texlive-bin",
  473. "latexmk" => "texlive-core",
  474. "rsvg-convert" => "extra/librsvg",
  475. );
  476. my @archlinux_tex_pkgs = (
  477. "texlive-core",
  478. "texlive-latexextra",
  479. "ttf-dejavu",
  480. );
  481. check_pacman_missing(\@archlinux_tex_pkgs, 2) if ($pdf);
  482. if ($pdf) {
  483. check_missing_file(["/usr/share/fonts/noto-cjk/NotoSansCJK-Regular.ttc"],
  484. "noto-fonts-cjk", 2);
  485. }
  486. check_missing(\%map);
  487. return if (!$need && !$optional);
  488. printf("You should run:\n\n\tsudo pacman -S $install\n");
  489. }
  490. sub give_gentoo_hints()
  491. {
  492. my %map = (
  493. "sphinx_rtd_theme" => "dev-python/sphinx_rtd_theme",
  494. "virtualenv" => "dev-python/virtualenv",
  495. "dot" => "media-gfx/graphviz",
  496. "convert" => "media-gfx/imagemagick",
  497. "xelatex" => "dev-texlive/texlive-xetex media-fonts/dejavu",
  498. "rsvg-convert" => "gnome-base/librsvg",
  499. );
  500. check_missing_file(["/usr/share/fonts/dejavu/DejaVuSans.ttf"],
  501. "media-fonts/dejavu", 2) if ($pdf);
  502. if ($pdf) {
  503. check_missing_file(["/usr/share/fonts/noto-cjk/NotoSansCJKsc-Regular.otf",
  504. "/usr/share/fonts/noto-cjk/NotoSerifCJK-Regular.ttc"],
  505. "media-fonts/noto-cjk", 2);
  506. }
  507. check_missing(\%map);
  508. return if (!$need && !$optional);
  509. printf("You should run:\n\n");
  510. my $imagemagick = "media-gfx/imagemagick svg png";
  511. my $cairo = "media-gfx/graphviz cairo pdf";
  512. my $portage_imagemagick = "/etc/portage/package.use/imagemagick";
  513. my $portage_cairo = "/etc/portage/package.use/graphviz";
  514. if (qx(grep imagemagick $portage_imagemagick 2>/dev/null) eq "") {
  515. printf("\tsudo su -c 'echo \"$imagemagick\" > $portage_imagemagick'\n")
  516. }
  517. if (qx(grep graphviz $portage_cairo 2>/dev/null) eq "") {
  518. printf("\tsudo su -c 'echo \"$cairo\" > $portage_cairo'\n");
  519. }
  520. printf("\tsudo emerge --ask $install\n");
  521. }
  522. sub check_distros()
  523. {
  524. # Distro-specific hints
  525. if ($system_release =~ /Red Hat Enterprise Linux/) {
  526. give_redhat_hints;
  527. return;
  528. }
  529. if ($system_release =~ /CentOS/) {
  530. give_redhat_hints;
  531. return;
  532. }
  533. if ($system_release =~ /Scientific Linux/) {
  534. give_redhat_hints;
  535. return;
  536. }
  537. if ($system_release =~ /Oracle Linux Server/) {
  538. give_redhat_hints;
  539. return;
  540. }
  541. if ($system_release =~ /Fedora/) {
  542. give_redhat_hints;
  543. return;
  544. }
  545. if ($system_release =~ /Ubuntu/) {
  546. give_debian_hints;
  547. return;
  548. }
  549. if ($system_release =~ /Debian/) {
  550. give_debian_hints;
  551. return;
  552. }
  553. if ($system_release =~ /openSUSE/) {
  554. give_opensuse_hints;
  555. return;
  556. }
  557. if ($system_release =~ /Mageia/) {
  558. give_mageia_hints;
  559. return;
  560. }
  561. if ($system_release =~ /OpenMandriva/) {
  562. give_mageia_hints;
  563. return;
  564. }
  565. if ($system_release =~ /Arch Linux/) {
  566. give_arch_linux_hints;
  567. return;
  568. }
  569. if ($system_release =~ /Gentoo/) {
  570. give_gentoo_hints;
  571. return;
  572. }
  573. #
  574. # Fall-back to generic hint code for other distros
  575. # That's far from ideal, specially for LaTeX dependencies.
  576. #
  577. my %map = (
  578. "sphinx-build" => "sphinx"
  579. );
  580. check_missing_tex(2) if ($pdf);
  581. check_missing(\%map);
  582. print "I don't know distro $system_release.\n";
  583. print "So, I can't provide you a hint with the install procedure.\n";
  584. print "There are likely missing dependencies.\n";
  585. }
  586. #
  587. # Common dependencies
  588. #
  589. sub deactivate_help()
  590. {
  591. printf "\nIf you want to exit the virtualenv, you can use:\n";
  592. printf "\tdeactivate\n";
  593. }
  594. sub check_needs()
  595. {
  596. # Check if Sphinx is already accessible from current environment
  597. check_sphinx();
  598. if ($system_release) {
  599. print "Detected OS: $system_release.\n";
  600. } else {
  601. print "Unknown OS\n";
  602. }
  603. printf "Sphinx version: %s\n\n", $cur_version if ($cur_version);
  604. # Check python command line, trying first python3
  605. $python_cmd = findprog("python3");
  606. $python_cmd = check_program("python", 0) if (!$python_cmd);
  607. # Check the type of virtual env, depending on Python version
  608. if ($python_cmd) {
  609. if ($virtualenv) {
  610. my $tmp = qx($python_cmd --version 2>&1);
  611. if ($tmp =~ m/(\d+\.)(\d+\.)/) {
  612. if ($1 >= 3 && $2 >= 3) {
  613. $need_venv = 1; # python 3.3 or upper
  614. } else {
  615. $need_virtualenv = 1;
  616. }
  617. if ($1 < 3) {
  618. # Complain if it finds python2 (or worse)
  619. printf "Warning: python$1 support is deprecated. Use it with caution!\n";
  620. }
  621. } else {
  622. die "Warning: couldn't identify $python_cmd version!";
  623. }
  624. } else {
  625. add_package("python-sphinx", 0);
  626. }
  627. }
  628. # Set virtualenv command line, if python < 3.3
  629. my $virtualenv_cmd;
  630. if ($need_virtualenv) {
  631. $virtualenv_cmd = findprog("virtualenv-3");
  632. $virtualenv_cmd = findprog("virtualenv-3.5") if (!$virtualenv_cmd);
  633. if (!$virtualenv_cmd) {
  634. check_program("virtualenv", 0);
  635. $virtualenv_cmd = "virtualenv";
  636. }
  637. }
  638. # Check for needed programs/tools
  639. check_perl_module("Pod::Usage", 0);
  640. check_program("make", 0);
  641. check_program("gcc", 0);
  642. check_python_module("sphinx_rtd_theme", 1) if (!$virtualenv);
  643. check_program("dot", 1);
  644. check_program("convert", 1);
  645. # Extra PDF files - should use 2 for is_optional
  646. check_program("xelatex", 2) if ($pdf);
  647. check_program("rsvg-convert", 2) if ($pdf);
  648. check_program("latexmk", 2) if ($pdf);
  649. if ($need_sphinx || $rec_sphinx_upgrade) {
  650. check_python_module("ensurepip", 0) if ($need_venv);
  651. }
  652. # Do distro-specific checks and output distro-install commands
  653. check_distros();
  654. if (!$python_cmd) {
  655. if ($need == 1) {
  656. die "Can't build as $need mandatory dependency is missing";
  657. } elsif ($need) {
  658. die "Can't build as $need mandatory dependencies are missing";
  659. }
  660. }
  661. # Check if sphinx-build is called sphinx-build-3
  662. if ($need_symlink) {
  663. printf "\tsudo ln -sf %s /usr/bin/sphinx-build\n\n",
  664. which("sphinx-build-3");
  665. }
  666. # NOTE: if the system has a too old Sphinx version installed,
  667. # it will recommend installing a newer version using virtualenv
  668. if ($need_sphinx || $rec_sphinx_upgrade) {
  669. my $min_activate = "$ENV{'PWD'}/${virtenv_prefix}${min_version}/bin/activate";
  670. my @activates = glob "$ENV{'PWD'}/${virtenv_prefix}*/bin/activate";
  671. if ($cur_version lt $rec_version) {
  672. print "Warning: It is recommended at least Sphinx version $rec_version.\n";
  673. print " If you want pdf, you need at least $min_pdf_version.\n";
  674. }
  675. if ($cur_version lt $min_pdf_version) {
  676. print "Note: It is recommended at least Sphinx version $min_pdf_version if you need PDF support.\n";
  677. }
  678. @activates = sort {$b cmp $a} @activates;
  679. my ($activate, $ver);
  680. foreach my $f (@activates) {
  681. next if ($f lt $min_activate);
  682. my $sphinx_cmd = $f;
  683. $sphinx_cmd =~ s/activate/sphinx-build/;
  684. next if (! -f $sphinx_cmd);
  685. $ver = get_sphinx_version($sphinx_cmd);
  686. if ($need_sphinx && ($ver ge $min_version)) {
  687. $activate = $f;
  688. last;
  689. } elsif ($ver gt $cur_version) {
  690. $activate = $f;
  691. last;
  692. }
  693. }
  694. if ($activate ne "") {
  695. if ($need_sphinx) {
  696. printf "\nNeed to activate Sphinx (version $ver) on virtualenv with:\n";
  697. printf "\t. $activate\n";
  698. deactivate_help();
  699. exit (1);
  700. } else {
  701. printf "\nYou may also use a newer Sphinx (version $ver) with:\n";
  702. printf "\tdeactivate && . $activate\n";
  703. }
  704. } else {
  705. my $rec_activate = "$virtenv_dir/bin/activate";
  706. print "To upgrade Sphinx, use:\n\n" if ($rec_sphinx_upgrade);
  707. $python_cmd = find_python_no_venv();
  708. if ($need_venv) {
  709. printf "\t$python_cmd -m venv $virtenv_dir\n";
  710. } else {
  711. printf "\t$virtualenv_cmd $virtenv_dir\n";
  712. }
  713. printf "\t. $rec_activate\n";
  714. printf "\tpip install -r $requirement_file\n";
  715. deactivate_help();
  716. $need++ if (!$rec_sphinx_upgrade);
  717. }
  718. }
  719. printf "\n";
  720. print "All optional dependencies are met.\n" if (!$optional);
  721. if ($need == 1) {
  722. die "Can't build as $need mandatory dependency is missing";
  723. } elsif ($need) {
  724. die "Can't build as $need mandatory dependencies are missing";
  725. }
  726. print "Needed package dependencies are met.\n";
  727. }
  728. #
  729. # Main
  730. #
  731. while (@ARGV) {
  732. my $arg = shift(@ARGV);
  733. if ($arg eq "--no-virtualenv") {
  734. $virtualenv = 0;
  735. } elsif ($arg eq "--no-pdf"){
  736. $pdf = 0;
  737. } elsif ($arg eq "--version-check"){
  738. $version_check = 1;
  739. } else {
  740. print "Usage:\n\t$0 <--no-virtualenv> <--no-pdf> <--version-check>\n\n";
  741. print "Where:\n";
  742. print "\t--no-virtualenv\t- Recommend installing Sphinx instead of using a virtualenv\n";
  743. print "\t--version-check\t- if version is compatible, don't check for missing dependencies\n";
  744. print "\t--no-pdf\t- don't check for dependencies required to build PDF docs\n\n";
  745. exit -1;
  746. }
  747. }
  748. #
  749. # Determine the system type. There's no standard unique way that would
  750. # work with all distros with a minimal package install. So, several
  751. # methods are used here.
  752. #
  753. # By default, it will use lsb_release function. If not available, it will
  754. # fail back to reading the known different places where the distro name
  755. # is stored
  756. #
  757. $system_release = qx(lsb_release -d) if which("lsb_release");
  758. $system_release =~ s/Description:\s*// if ($system_release);
  759. $system_release = catcheck("/etc/system-release") if !$system_release;
  760. $system_release = catcheck("/etc/redhat-release") if !$system_release;
  761. $system_release = catcheck("/etc/lsb-release") if !$system_release;
  762. $system_release = catcheck("/etc/gentoo-release") if !$system_release;
  763. # This seems more common than LSB these days
  764. if (!$system_release) {
  765. my %os_var;
  766. if (open IN, "cat /etc/os-release|") {
  767. while (<IN>) {
  768. if (m/^([\w\d\_]+)=\"?([^\"]*)\"?\n/) {
  769. $os_var{$1}=$2;
  770. }
  771. }
  772. $system_release = $os_var{"NAME"};
  773. if (defined($os_var{"VERSION_ID"})) {
  774. $system_release .= " " . $os_var{"VERSION_ID"} if (defined($os_var{"VERSION_ID"}));
  775. } else {
  776. $system_release .= " " . $os_var{"VERSION"};
  777. }
  778. }
  779. }
  780. $system_release = catcheck("/etc/issue") if !$system_release;
  781. $system_release =~ s/\s+$//;
  782. check_needs;