History

scripts: sphinx-pre-install: move missing logic to a separate class

Better manage dependencies by placing them on a distro-independent class.

Mauro Carvalho Chehab committed 1 year ago

Commit 2cab00f1 parent 272f5e01 file · +138 −113Browse files

Unified · Split

scripts/sphinx-pre-install.py+138−113
@@ -32,7 +32,7 @@ RECOMMENDED_VERSION = parse_version("3.4.3") · 31 unmodified lines
3232 MIN_PYTHON_VERSION = parse_version("3.7")
3333
3434
35−class DepType:
35+class DepManager:
3636
3737 # Internal types of dependencies.
3838 _SYS_TYPE = 0
@@ -53,11 +53,18 @@ class DepType: · 14 unmodified lines
5353 PYTHON_OPTIONAL = (_PHY_TYPE, False)
5454 PDF_OPTIONAL = (_PDF_TYPE, True)
5555
56+ def __init__(self, pdf):
57+ self.missing = {}
58+ self.run = {}
59+ self.need = 0
60+ self.optional = 0
61+ self.pdf = pdf
62+
5663 @staticmethod
5764 def name(dtype):
58− if dtype[0] == DepType._SYS_TYPE:
65+ if dtype[0] == DepManager._SYS_TYPE:
5966 msg = "build"
60− elif dtype[0] == DepType._PHY_TYPE:
67+ elif dtype[0] == DepManager._PHY_TYPE:
6168 msg = "Python"
6269 else:
6370 msg = "PDF"
@@ -73,11 +80,75 @@ class DepType: · 9 unmodified lines
7380
7481 @staticmethod
7582 def is_pdf(dtype):
76− if (dtype[0] == DepType._PDF_TYPE):
83+ if (dtype[0] == DepManager._PDF_TYPE):
7784 return True
7885
7986 return False
8087
88+ def add_package(self, package, dtype):
89+ is_optional = DepManager.is_optional(dtype)
90+ self.missing[package] = dtype
91+ if is_optional:
92+ self.optional += 1
93+ else:
94+ self.need += 1
95+
96+ def del_package(self, package):
97+ if package in self.missing:
98+ del self.missing[package]
99+
100+ def clear_deps(self):
101+ """
102+ Clear dependencies without changing needed/optional.
103+
104+ This is an ackward way to have a separate section to recommend
105+ a package after system main dependencies.
106+
107+ TODO: rework the logic to prevent needing it
108+ """
109+
110+ self.missing = {}
111+
112+ def check_missing(self, progs):
113+ self.run = {}
114+
115+ for prog, dtype in sorted(self.missing.items()):
116+ # At least on some LTS distros like CentOS 7, texlive doesn't
117+ # provide all packages we need. When such distros are
118+ # detected, we have to disable PDF output.
119+ #
120+ # So, we need to ignore the packages that distros would
121+ # need for LaTeX to work
122+ if DepManager.is_pdf(dtype) and not self.pdf:
123+ self.optional -= 1
124+ continue
125+
126+ if not dtype in self.run:
127+ self.run[dtype] = []
128+
129+ self.run[dtype].append(progs.get(prog, prog))
130+
131+ install = []
132+ for dtype in self.run.keys():
133+ install += self.run[dtype]
134+
135+ return " ".join(sorted(set(install)))
136+
137+ def warn_install(self):
138+
139+ output_msg = ""
140+
141+ for dtype in sorted(self.run.keys()):
142+ progs = " ".join(sorted(set(self.run[dtype])))
143+
144+ try:
145+ name = DepManager.name(dtype)
146+ output_msg += f'{name}:\t{progs}\n'
147+ except KeyError:
148+ raise KeyError(f"ERROR!!!: invalid dtype for {progs}: {dtype}")
149+
150+ if output_msg:
151+ print(f"\n{output_msg}\n")
81152
82153 class SphinxDependencyChecker:
83154 # List of required texlive packages on Fedora and OpenSuse
@@ -120,10 +191,8 @@ class SphinxDependencyChecker: · 36 unmodified lines
120191 self.virtualenv = args.virtualenv
121192 self.version_check = args.version_check
122193
123− self.missing = {}
194+ self.deps = DepManager(self.pdf)
124195
125− self.need = 0
126− self.optional = 0
127196 self.need_symlink = 0
128197 self.need_sphinx = 0
129198 self.need_pip = 0
@@ -270,64 +339,18 @@ class SphinxDependencyChecker: · 140 unmodified lines
270339 # Methods to check if a feature exists
271340 #
272341
273− def check_missing(self, progs):
274− run = {}
275−
276− for prog, dtype in sorted(self.missing.items()):
277− # At least on some LTS distros like CentOS 7, texlive doesn't
278− # provide all packages we need. When such distros are
279− # detected, we have to disable PDF output.
280− #
281− # So, we need to ignore the packages that distros would
282− # need for LaTeX to work
283− if DepType.is_pdf(dtype) and not self.pdf:
284− self.optional -= 1
285− continue
286−
287− if not dtype in run:
288− run[dtype] = []
289−
290− run[dtype].append(prog)
291−
292− output_msg = ""
293−
294− for dtype in sorted(run.keys()):
295− progs = " ".join(run[dtype])
296−
297− if self.verbose_warn_install:
298− try:
299− name = DepType.name(dtype)
300− output_msg += f'{name}:\t{progs}\n'
301− except KeyError:
302− raise KeyError(f"ERROR!!!: invalid dtype for {progs}: {dtype}")
303−
304− self.install += " " + progs
305−
306− if output_msg:
307− print(f"\n{output_msg}\n")
308−
309− self.install = self.install.lstrip()
310−
311− def add_package(self, package, dtype):
312− is_optional = DepType.is_optional(dtype)
313− self.missing[package] = dtype
314− if is_optional:
315− self.optional += 1
316− else:
317− self.need += 1
318−
319342 def check_missing_file(self, files, package, dtype):
320343 for f in files:
321344 if os.path.exists(f):
322345 return
323− self.add_package(package, dtype)
346+ self.deps.add_package(package, dtype)
324347
325348 def check_program(self, prog, dtype):
326349 found = self.which(prog)
327350 if found:
328351 return found
329352
330− self.add_package(prog, dtype)
353+ self.deps.add_package(prog, dtype)
331354
332355 return None
333356
@@ -340,52 +363,52 @@ class SphinxDependencyChecker: · 6 unmodified lines
340363 # add it as a mandatory package, as some parts of the doc builder
341364 # needs it.
342365 if not self.which("perl"):
343− self.add_package("perl", DepType.SYSTEM_MANDATORY)
344− self.add_package(prog, dtype)
366+ self.deps.add_package("perl", DepManager.SYSTEM_MANDATORY)
367+ self.deps.add_package(prog, dtype)
345368 return
346369
347370 try:
348371 self.run(["perl", f"-M{prog}", "-e", "1"], check=True)
349372 except subprocess.CalledProcessError:
350− self.add_package(prog, dtype)
373+ self.deps.add_package(prog, dtype)
351374
352375 def check_python_module(self, module, is_optional=False):
353376 if is_optional:
354− dtype = DepType.PYTHON_OPTIONAL
377+ dtype = DepManager.PYTHON_OPTIONAL
355378 else:
356− dtype = DepType.PYTHON_MANDATORY
379+ dtype = DepManager.PYTHON_MANDATORY
357380
358381 try:
359382 self.run([self.python_cmd, "-c", f"import {module}"], check=True)
360383 except subprocess.CalledProcessError:
361− self.add_package(module, dtype)
384+ self.deps.add_package(module, dtype)
362385
363386 def check_rpm_missing(self, pkgs, dtype):
364387 for prog in pkgs:
365388 try:
366389 self.run(["rpm", "-q", prog], check=True)
367390 except subprocess.CalledProcessError:
368− self.add_package(prog, dtype)
391+ self.deps.add_package(prog, dtype)
369392
370393 def check_pacman_missing(self, pkgs, dtype):
371394 for prog in pkgs:
372395 try:
373396 self.run(["pacman", "-Q", prog], check=True)
374397 except subprocess.CalledProcessError:
375− self.add_package(prog, dtype)
398+ self.deps.add_package(prog, dtype)
376399
377400 def check_missing_tex(self, is_optional=False):
378401 if is_optional:
379− dtype = DepType.PDF_OPTIONAL
402+ dtype = DepManager.PDF_OPTIONAL
380403 else:
381− dtype = DepType.PDF_MANDATORY
404+ dtype = DepManager.PDF_MANDATORY
382405
383406 kpsewhich = self.which("kpsewhich")
384407 for prog, package in self.texlive.items():
385408
386409 # If kpsewhich is not there, just add it to deps
387410 if not kpsewhich:
388− self.add_package(package, dtype)
411+ self.deps.add_package(package, dtype)
389412 continue
390413
391414 # Check if the package is needed
@@ -396,11 +419,11 @@ class SphinxDependencyChecker: · 4 unmodified lines
396419
397420 # Didn't find. Add it
398421 if not result.stdout.strip():
399− self.add_package(package, dtype)
422+ self.deps.add_package(package, dtype)
400423
401424 except subprocess.CalledProcessError:
402425 # kpsewhich returned an error. Add it, just in case
403− self.add_package(package, dtype)
426+ self.deps.add_package(package, dtype)
404427
405428 def get_sphinx_fname(self):
406429 if "SPHINXBUILD" in os.environ:
@@ -478,6 +501,17 @@ class SphinxDependencyChecker: · 71 unmodified lines
478501 return f.read().strip()
479502 return ""
480503
504+ def check_missing(self, progs):
505+ self.install += self.deps.check_missing(progs)
506+ if self.verbose_warn_install:
507+ self.deps.warn_install()
508+
509+ if not self.deps.need and not self.deps.optional:
510+ return False
511+
512+ return True
513+
514+
481515 #
482516 # Distro-specific hints methods
483517 #
@@ -511,13 +545,11 @@ class SphinxDependencyChecker: · 27 unmodified lines
511545 }
512546
513547 for package, files in pdf_pkgs.items():
514− self.check_missing_file(files, package, DepType.PDF_MANDATORY)
515−
516− self.check_program("dvipng", DepType.PDF_MANDATORY)
548+ self.check_missing_file(files, package, DepManager.PDF_MANDATORY)
517549
518− self.check_missing(progs)
550+ self.check_program("dvipng", DepManager.PDF_MANDATORY)
519551
520− if not self.need and not self.optional:
552+ if self.check_missing(progs):
521553 return
522554
523555 if self.verbose_warn_install:
@@ -575,7 +607,7 @@ class SphinxDependencyChecker: · 51 unmodified lines
575607 # RHEL 8 uses Python 3.6, which is not compatible with
576608 # the build system anymore. Suggest Python 3.11
577609 if rel == 8:
578− self.add_package("python39", DepType.SYSTEM_MANDATORY)
610+ self.deps.add_package("python39", DepManager.SYSTEM_MANDATORY)
579611 self.recommend_python = True
580612
581613 if self.first_hint:
@@ -597,22 +629,18 @@ class SphinxDependencyChecker: · 15 unmodified lines
597629 "/usr/share/fonts/google-noto-sans-cjk-fonts/NotoSansCJK-Regular.ttc",
598630 ]
599631
600− self.check_missing_file(pdf_pkgs, noto_sans_redhat, DepType.PDF_MANDATORY)
632+ self.check_missing_file(pdf_pkgs, noto_sans_redhat, DepManager.PDF_MANDATORY)
601633
602− self.check_rpm_missing(fedora_tex_pkgs, DepType.PDF_MANDATORY)
634+ self.check_rpm_missing(fedora_tex_pkgs, DepManager.PDF_MANDATORY)
603635
604− self.check_missing_tex(DepType.PDF_MANDATORY)
636+ self.check_missing_tex(DepManager.PDF_MANDATORY)
605637
606638 # There's no texlive-ctex on RHEL 8 repositories. This will
607639 # likely affect CJK pdf build only.
608640 if not fedora and rel == 8:
609− if "texlive-ctex" in self.missing:
610− del self.missing["texlive-ctex"]
611−
612−
613− self.check_missing(progs)
641+ self.deps.del_package("texlive-ctex")
614642
615− if not self.need and not self.optional:
643+ if self.check_missing(progs):
616644 return
617645
618646 if self.verbose_warn_install:
@@ -659,7 +687,7 @@ class SphinxDependencyChecker: · 40 unmodified lines
659687 if rel == 15:
660688 if not self.which(self.python_cmd):
661689 self.recommend_python = True
662− self.add_package(self.python_cmd, DepType.SYSTEM_MANDATORY)
690+ self.deps.add_package(self.python_cmd, DepManager.SYSTEM_MANDATORY)
663691
664692 progs.update({
665693 "python-sphinx": "python311-Sphinx",
@@ -681,12 +709,11 @@ class SphinxDependencyChecker: · 15 unmodified lines
681709 # "Noto Sans CJK SC" on openSUSE
682710
683711 if self.pdf:
684− self.check_rpm_missing(suse_tex_pkgs, DepType.PDF_MANDATORY)
712+ self.check_rpm_missing(suse_tex_pkgs, DepManager.PDF_MANDATORY)
685713 if self.pdf:
686714 self.check_missing_tex()
687− self.check_missing(progs)
688715
689− if not self.need and not self.optional:
716+ if self.check_missing(progs):
690717 return
691718
692719 if self.verbose_warn_install:
@@ -730,13 +757,12 @@ class SphinxDependencyChecker: · 37 unmodified lines
730757 "/usr/share/fonts/TTF/NotoSans-Regular.ttf",
731758 ]
732759
733− self.check_missing_file(pdf_pkgs, noto_sans, DepType.PDF_MANDATORY)
734− self.check_rpm_missing(tex_pkgs, DepType.PDF_MANDATORY)
735−
736− self.check_missing(progs)
760+ self.check_missing_file(pdf_pkgs, noto_sans, DepManager.PDF_MANDATORY)
761+ self.check_rpm_missing(tex_pkgs, DepManager.PDF_MANDATORY)
737762
738− if not self.need and not self.optional:
763+ if self.check_missing(progs):
739764 return
765+
740766 if self.verbose_warn_install:
741767 print("You should run:")
742768 print(f"\n\tsudo {packager_cmd} {self.install}")
@@ -759,7 +785,7 @@ class SphinxDependencyChecker: · 16 unmodified lines
759785 ]
760786
761787 if self.pdf:
762− self.check_pacman_missing(archlinux_tex_pkgs, DepType.PDF_MANDATORY)
788+ self.check_pacman_missing(archlinux_tex_pkgs, DepManager.PDF_MANDATORY)
763789
764790 self.check_missing_file(
765791 ["/usr/share/fonts/noto-cjk/NotoSansCJK-Regular.ttc"],
@@ -767,10 +793,9 @@ class SphinxDependencyChecker: · 1 unmodified line
767793 2,
768794 )
769795
770− self.check_missing(progs)
771−
772− if not self.need and not self.optional:
796+ if self.check_missing(progs):
773797 return
798+
774799 if self.verbose_warn_install:
775800 print("You should run:")
776801 print(f"\n\tsudo pacman -S {self.install}")
@@ -797,11 +822,9 @@ class SphinxDependencyChecker: · 20 unmodified lines
797822 ],
798823 }
799824 for package, files in pdf_pkgs.items():
800− self.check_missing_file(files, package, DepType.PDF_MANDATORY)
801−
802− self.check_missing(progs)
825+ self.check_missing_file(files, package, DepManager.PDF_MANDATORY)
803826
804− if not self.need and not self.optional:
827+ if self.check_missing(progs):
805828 return
806829
807830 if self.verbose_warn_install:
@@ -1039,16 +1062,18 @@ class SphinxDependencyChecker: · 231 unmodified lines
10391062
10401063 print("\n2) As a package with:")
10411064
1042− old_need = self.need
1043− old_optional = self.optional
1044− self.missing = {}
1065+ old_need = self.deps.need
1066+ old_optional = self.deps.optional
1067+
10451068 self.pdf = False
10461069 self.optional = 0
10471070 self.install = ""
10481071 old_verbose = self.verbose_warn_install
10491072 self.verbose_warn_install = 0
10501073
1051− self.add_package("python-sphinx", DepType.PYTHON_MANDATORY)
1074+ self.deps.clear_deps()
1075+
1076+ self.deps.add_package("python-sphinx", DepManager.PYTHON_MANDATORY)
10521077
10531078 self.check_distros()
10541079
@@ -1111,7 +1136,7 @@ class SphinxDependencyChecker: · 56 unmodified lines
11111136 print("\n")
11121137 else:
11131138 if self.need_sphinx:
1114− self.need += 1
1139+ self.deps.need += 1
11151140
11161141 # Suggest newer versions if current ones are too old
11171142 if self.latest_avail_ver and self.latest_avail_ver >= self.min_version:
@@ -1190,20 +1215,20 @@ class SphinxDependencyChecker: · 72 unmodified lines
11901215 self.check_python_module("ensurepip")
11911216
11921217 # Check for needed programs/tools
1193− self.check_perl_module("Pod::Usage", DepType.SYSTEM_MANDATORY)
1218+ self.check_perl_module("Pod::Usage", DepManager.SYSTEM_MANDATORY)
11941219
1195− self.check_program("make", DepType.SYSTEM_MANDATORY)
1196− self.check_program("gcc", DepType.SYSTEM_MANDATORY)
1220+ self.check_program("make", DepManager.SYSTEM_MANDATORY)
1221+ self.check_program("gcc", DepManager.SYSTEM_MANDATORY)
11971222
1198− self.check_program("dot", DepType.SYSTEM_OPTIONAL)
1199− self.check_program("convert", DepType.SYSTEM_OPTIONAL)
1223+ self.check_program("dot", DepManager.SYSTEM_OPTIONAL)
1224+ self.check_program("convert", DepManager.SYSTEM_OPTIONAL)
12001225
12011226 self.check_python_module("yaml")
12021227
12031228 if self.pdf:
1204− self.check_program("xelatex", DepType.PDF_MANDATORY)
1205− self.check_program("rsvg-convert", DepType.PDF_MANDATORY)
1206− self.check_program("latexmk", DepType.PDF_MANDATORY)
1229+ self.check_program("xelatex", DepManager.PDF_MANDATORY)
1230+ self.check_program("rsvg-convert", DepManager.PDF_MANDATORY)
1231+ self.check_program("latexmk", DepManager.PDF_MANDATORY)
12071232
12081233 # Do distro-specific checks and output distro-install commands
12091234 self.check_distros()