History

scripts: sphinx-pre-install: convert is_optional to a class

When is_optional was added in Perl, it was a boolean. With time, it ended becoming a sort of enum, which makes the module harder to maintain. Convert it to a enum-like class and add more options to it.

Mauro Carvalho Chehab committed 1 year ago

Commit 9ecda2e1 parent 8cd25651 file · +130 −62Browse files

Showing the changes to scripts (1 of 1 file). Show all

Unified · Split

scripts/sphinx-pre-install.py+130−62
@@ -32,6 +32,53 @@ RECOMMENDED_VERSION = parse_version("3.4.3") · 31 unmodified lines
3232 MIN_PYTHON_VERSION = parse_version("3.7")
3333
3434
35+class DepType:
36+
37+ # Internal types of dependencies.
38+ _SYS_TYPE = 0
39+ _PHY_TYPE = 1
40+ _PDF_TYPE = 2
41+
42+ # Let's define keys as a tuple with the type and mandatory/optional.
43+ # This way, checking for optional or type is easy.
44+
45+ SYSTEM_MANDATORY = (_SYS_TYPE, True)
46+ PYTHON_MANDATORY = (_PHY_TYPE, True)
47+ PDF_MANDATORY = (_PDF_TYPE, True)
48+
49+ # Currently we're not using all optional types, but let's keep all
50+ # combinations here, as we may end needing them in the future. Also,
51+ # it allows a name() function that handles all possibilities.
52+ SYSTEM_OPTIONAL = (_SYS_TYPE, False)
53+ PYTHON_OPTIONAL = (_PHY_TYPE, False)
54+ PDF_OPTIONAL = (_PDF_TYPE, True)
55+
56+ @staticmethod
57+ def name(dtype):
58+ if dtype[0] == DepType._SYS_TYPE:
59+ msg = "build"
60+ elif dtype[0] == DepType._PHY_TYPE:
61+ msg = "Python"
62+ else:
63+ msg = "PDF"
64+
65+ if dtype[1]:
66+ return f"ERROR: {msg} mandatory deps missing"
67+ else:
68+ out = f"Warning: {msg} optional deps missing"
69+
70+ @staticmethod
71+ def is_optional(dtype):
72+ return not dtype[1]
73+
74+ @staticmethod
75+ def is_pdf(dtype):
76+ if (dtype[0] == DepType._PDF_TYPE):
77+ return True
78+
79+ return False
80+
81+
3582 class SphinxDependencyChecker:
3683 # List of required texlive packages on Fedora and OpenSuse
3784 texlive = {
@@ -223,56 +270,68 @@ class SphinxDependencyChecker: · 185 unmodified lines
223270 # Methods to check if a feature exists
224271 #
225272
226− # Note: is_optional has 3 states:
227− # - 0: mandatory
228− # - 1: optional, but nice to have
229− # - 2: LaTeX optional - pdf builds without it, but may have visual impact
230−
231273 def check_missing(self, progs):
232− for prog, is_optional in sorted(self.missing.items()):
274+ run = {}
275+
276+ for prog, dtype in sorted(self.missing.items()):
233277 # At least on some LTS distros like CentOS 7, texlive doesn't
234278 # provide all packages we need. When such distros are
235279 # detected, we have to disable PDF output.
236280 #
237281 # So, we need to ignore the packages that distros would
238282 # need for LaTeX to work
239− if is_optional == 2 and not self.pdf:
283+ if DepType.is_pdf(dtype) and not self.pdf:
240284 self.optional -= 1
241285 continue
242286
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+
243297 if self.verbose_warn_install:
244− if is_optional:
245− print(f'Warning: better to also install "{prog}".')
246− else:
247− print(f'ERROR: please install "{prog}", otherwise, build won\'t work.')
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}")
248303
249− self.install += " " + progs.get(prog, prog)
304+ self.install += " " + progs
305+
306+ if output_msg:
307+ print(f"\n{output_msg}\n")
250308
251309 self.install = self.install.lstrip()
252310
253− def add_package(self, package, is_optional):
254− self.missing[package] = is_optional
311+ def add_package(self, package, dtype):
312+ is_optional = DepType.is_optional(dtype)
313+ self.missing[package] = dtype
255314 if is_optional:
256315 self.optional += 1
257316 else:
258317 self.need += 1
259318
260− def check_missing_file(self, files, package, is_optional):
319+ def check_missing_file(self, files, package, dtype):
261320 for f in files:
262321 if os.path.exists(f):
263322 return
264− self.add_package(package, is_optional)
323+ self.add_package(package, dtype)
265324
266− def check_program(self, prog, is_optional):
325+ def check_program(self, prog, dtype):
267326 found = self.which(prog)
268327 if found:
269328 return found
270329
271− self.add_package(prog, is_optional)
330+ self.add_package(prog, dtype)
272331
273332 return None
274333
275− def check_perl_module(self, prog, is_optional):
334+ def check_perl_module(self, prog, dtype):
276335 # While testing with lxc download template, one of the
277336 # distros (Oracle) didn't have perl - nor even an option to install
278337 # before installing oraclelinux-release-el9 package.
@@ -281,46 +340,52 @@ class SphinxDependencyChecker: · 2 unmodified lines
281340 # add it as a mandatory package, as some parts of the doc builder
282341 # needs it.
283342 if not self.which("perl"):
284− self.add_package("perl", 0)
285− self.add_package(prog, is_optional)
343+ self.add_package("perl", DepType.SYSTEM_MANDATORY)
344+ self.add_package(prog, dtype)
286345 return
287346
288347 try:
289348 self.run(["perl", f"-M{prog}", "-e", "1"], check=True)
290349 except subprocess.CalledProcessError:
291− self.add_package(prog, is_optional)
350+ self.add_package(prog, dtype)
292351
293− def check_python_module(self, module, is_optional):
294− # FIXME: is it needed at the Python version? Maybe due to venv?
295− if not self.python_cmd:
296− return
352+ def check_python_module(self, module, is_optional=False):
353+ if is_optional:
354+ dtype = DepType.PYTHON_OPTIONAL
355+ else:
356+ dtype = DepType.PYTHON_MANDATORY
297357
298358 try:
299359 self.run([self.python_cmd, "-c", f"import {module}"], check=True)
300360 except subprocess.CalledProcessError:
301− self.add_package(module, is_optional)
361+ self.add_package(module, dtype)
302362
303− def check_rpm_missing(self, pkgs, is_optional):
363+ def check_rpm_missing(self, pkgs, dtype):
304364 for prog in pkgs:
305365 try:
306366 self.run(["rpm", "-q", prog], check=True)
307367 except subprocess.CalledProcessError:
308− self.add_package(prog, is_optional)
368+ self.add_package(prog, dtype)
309369
310− def check_pacman_missing(self, pkgs, is_optional):
370+ def check_pacman_missing(self, pkgs, dtype):
311371 for prog in pkgs:
312372 try:
313373 self.run(["pacman", "-Q", prog], check=True)
314374 except subprocess.CalledProcessError:
315− self.add_package(prog, is_optional)
375+ self.add_package(prog, dtype)
376+
377+ def check_missing_tex(self, is_optional=False):
378+ if is_optional:
379+ dtype = DepType.PDF_OPTIONAL
380+ else:
381+ dtype = DepType.PDF_MANDATORY
316382
317− def check_missing_tex(self, is_optional):
318383 kpsewhich = self.which("kpsewhich")
319384 for prog, package in self.texlive.items():
320385
321386 # If kpsewhich is not there, just add it to deps
322387 if not kpsewhich:
323− self.add_package(package, is_optional)
388+ self.add_package(package, dtype)
324389 continue
325390
326391 # Check if the package is needed
@@ -331,11 +396,11 @@ class SphinxDependencyChecker: · 4 unmodified lines
331396
332397 # Didn't find. Add it
333398 if not result.stdout.strip():
334− self.add_package(package, is_optional)
399+ self.add_package(package, dtype)
335400
336401 except subprocess.CalledProcessError:
337402 # kpsewhich returned an error. Add it, just in case
338− self.add_package(package, is_optional)
403+ self.add_package(package, dtype)
339404
340405 def get_sphinx_fname(self):
341406 if "SPHINXBUILD" in os.environ:
@@ -446,9 +511,9 @@ class SphinxDependencyChecker: · 104 unmodified lines
446511 }
447512
448513 for package, files in pdf_pkgs.items():
449− self.check_missing_file(files, package, 2)
514+ self.check_missing_file(files, package, DepType.PDF_MANDATORY)
450515
451− self.check_program("dvipng", 2)
516+ self.check_program("dvipng", DepType.PDF_MANDATORY)
452517
453518 self.check_missing(progs)
454519
@@ -518,7 +583,7 @@ class SphinxDependencyChecker: · 63 unmodified lines
518583 # RHEL 8 uses Python 3.6, which is not compatible with
519584 # the build system anymore. Suggest Python 3.11
520585 if rel == 8:
521− self.add_package("python39", 0)
586+ self.add_package("python39", DepType.SYSTEM_MANDATORY)
522587 self.recommend_python = True
523588
524589 if self.first_hint:
@@ -540,13 +605,13 @@ class SphinxDependencyChecker: · 15 unmodified lines
540605 "/usr/share/fonts/google-noto-sans-cjk-fonts/NotoSansCJK-Regular.ttc",
541606 ]
542607
543− self.check_missing_file(pdf_pkgs, noto_sans_redhat, 2)
608+ self.check_missing_file(pdf_pkgs, noto_sans_redhat, DepType.PDF_MANDATORY)
544609
545610 if not old:
546− self.check_rpm_missing(fedora26_opt_pkgs, 2)
547− self.check_rpm_missing(fedora_tex_pkgs, 2)
611+ self.check_rpm_missing(fedora26_opt_pkgs, DepType.PDF_MANDATORY)
612+ self.check_rpm_missing(fedora_tex_pkgs, DepType.PDF_MANDATORY)
548613
549− self.check_missing_tex(2)
614+ self.check_missing_tex()
550615
551616 self.check_missing(progs)
552617
@@ -601,7 +666,7 @@ class SphinxDependencyChecker: · 48 unmodified lines
601666 if rel == 15:
602667 if not self.which(self.python_cmd):
603668 self.recommend_python = True
604− self.add_package(self.python_cmd, 0)
669+ self.add_package(self.python_cmd, DepType.SYSTEM_MANDATORY)
605670
606671 progs.update({
607672 "python-sphinx": "python311-Sphinx",
@@ -623,9 +688,9 @@ class SphinxDependencyChecker: · 15 unmodified lines
623688 # "Noto Sans CJK SC" on openSUSE
624689
625690 if self.pdf:
626− self.check_rpm_missing(suse_tex_pkgs, 2)
691+ self.check_rpm_missing(suse_tex_pkgs, DepType.PDF_MANDATORY)
627692 if self.pdf:
628− self.check_missing_tex(2)
693+ self.check_missing_tex()
629694 self.check_missing(progs)
630695
631696 if not self.need and not self.optional:
@@ -672,8 +737,8 @@ class SphinxDependencyChecker: · 40 unmodified lines
672737 "/usr/share/fonts/TTF/NotoSans-Regular.ttf",
673738 ]
674739
675− self.check_missing_file(pdf_pkgs, noto_sans, 2)
676− self.check_rpm_missing(tex_pkgs, 2)
740+ self.check_missing_file(pdf_pkgs, noto_sans, DepType.PDF_MANDATORY)
741+ self.check_rpm_missing(tex_pkgs, DepType.PDF_MANDATORY)
677742
678743 self.check_missing(progs)
679744
@@ -701,7 +766,7 @@ class SphinxDependencyChecker: · 21 unmodified lines
701766 ]
702767
703768 if self.pdf:
704− self.check_pacman_missing(archlinux_tex_pkgs, 2)
769+ self.check_pacman_missing(archlinux_tex_pkgs, DepType.PDF_MANDATORY)
705770
706771 self.check_missing_file(
707772 ["/usr/share/fonts/noto-cjk/NotoSansCJK-Regular.ttc"],
@@ -739,7 +804,7 @@ class SphinxDependencyChecker: · 31 unmodified lines
739804 ],
740805 }
741806 for package, files in pdf_pkgs.items():
742− self.check_missing_file(files, package, 2)
807+ self.check_missing_file(files, package, DepType.PDF_MANDATORY)
743808
744809 self.check_missing(progs)
745810
@@ -878,7 +943,7 @@ class SphinxDependencyChecker: · 132 unmodified lines
878943 #
879944 progs = {"sphinx-build": "sphinx"}
880945 if self.pdf:
881− self.check_missing_tex(2)
946+ self.check_missing_tex()
882947
883948 self.check_missing(progs)
884949
@@ -990,7 +1055,7 @@ class SphinxDependencyChecker: · 105 unmodified lines
9901055 old_verbose = self.verbose_warn_install
9911056 self.verbose_warn_install = 0
9921057
993− self.add_package("python-sphinx", 0)
1058+ self.add_package("python-sphinx", DepType.PYTHON_MANDATORY)
9941059
9951060 self.check_distros()
9961061
@@ -1010,6 +1075,7 @@ class SphinxDependencyChecker: · 13 unmodified lines
10101075 "Please upgrade it and re-run.\n")
10111076 return
10121077
1078+
10131079 # Version is OK. Nothing to do.
10141080 if self.cur_version != (0, 0, 0) and self.cur_version >= RECOMMENDED_VERSION:
10151081 return
@@ -1128,21 +1194,23 @@ class SphinxDependencyChecker: · 112 unmodified lines
11281194
11291195 else:
11301196 virtualenv_cmd = f"{self.python_cmd} -m venv"
1131− self.check_python_module("ensurepip", 0)
1197+ self.check_python_module("ensurepip")
11321198
11331199 # Check for needed programs/tools
1134− self.check_perl_module("Pod::Usage", 0)
1135− self.check_python_module("yaml", 0)
1136− self.check_program("make", 0)
1137− self.check_program("gcc", 0)
1138− self.check_program("dot", 1)
1139− self.check_program("convert", 1)
1200+ self.check_perl_module("Pod::Usage", DepType.SYSTEM_MANDATORY)
1201+
1202+ self.check_program("make", DepType.SYSTEM_MANDATORY)
1203+ self.check_program("gcc", DepType.SYSTEM_MANDATORY)
1204+
1205+ self.check_program("dot", DepType.SYSTEM_OPTIONAL)
1206+ self.check_program("convert", DepType.SYSTEM_OPTIONAL)
1207+
1208+ self.check_python_module("yaml")
11401209
11411210 if self.pdf:
1142− # Extra PDF files - should use 2 for LaTeX is_optional
1143− self.check_program("xelatex", 2)
1144− self.check_program("rsvg-convert", 2)
1145− self.check_program("latexmk", 2)
1211+ self.check_program("xelatex", DepType.PDF_MANDATORY)
1212+ self.check_program("rsvg-convert", DepType.PDF_MANDATORY)
1213+ self.check_program("latexmk", DepType.PDF_MANDATORY)
11461214
11471215 # Do distro-specific checks and output distro-install commands
11481216 self.check_distros()