From nobody Sat Oct 4 22:18:28 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BF70A2F83C8; Tue, 12 Aug 2025 15:53:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755013985; cv=none; b=gx19QgwZU9n90PSGSOnq2f+g5ILZ4ELSCYkhcA4gMRnhQqcGy/Bjpr1sdlf21woaGCKxDQVbgGJAeNwk4f/s6BvYgqkIIkIDQhmuttQR6fG4R2lTr6M2iRq56kIk1aDVUY9nSEg8xEBjKRJlYPgtTSksLjwx2dF86I2loeK0bFg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755013985; c=relaxed/simple; bh=fRpeYNnkO/XLm29IsXGOKl1Wayy/ayQJh5RKfx/WcYg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ERYR0tzO0fx7rGImiBvvMsgpY1ULran58oc/fD2tFmsYbckA6nJA29+k6HLx1sDe6esfLW4/llfeQ+jzG939WsODLbC+mVWVbTZOoJ2XQm4aK2opLpbthEcU37yBKTAoFI3CnB3tGbxtfp4a3BEQRfEfgvtD42jszHZ2XnaAtQE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=nh6VbEAk; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="nh6VbEAk" Received: by smtp.kernel.org (Postfix) with ESMTPSA id EBF0DC19422; Tue, 12 Aug 2025 15:53:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1755013985; bh=fRpeYNnkO/XLm29IsXGOKl1Wayy/ayQJh5RKfx/WcYg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=nh6VbEAkrpGkiQBmRU7Q1vWCDyxzxBiLDbL6eEKRzd6IwDHyGUuWNC0sxAPppOuUB G7GgcjkfLiMYjLkSkrQG1cXVjX6DDsM9fGtQzfK+8PsSXS9KdmxWkiqV/tVoTs2Duy ZCUWuardoRQ41Y3paTgBFURyEkBXxn1abKCNLU3UQ52L4uRNSf3oSulem+v/4ECLq2 P12j3A+N7gLLxQFy1++645wGgy8MPc6ikKViXlaI0xZB3VHcmoFWZ1e/OsO5rH/QnN 9nJocF8XtTCw7sdQa+GpGvPLXUd4AjdZo+pZ9JjbgrdmljfgO76CTAAC2MsegkpiPc i+kaSTtoAsPuA== Received: from mchehab by mail.kernel.org with local (Exim 4.98.2) (envelope-from ) id 1ulrJ8-00000006kWk-3DAF; Tue, 12 Aug 2025 17:53:02 +0200 From: Mauro Carvalho Chehab To: Linux Doc Mailing List Cc: Mauro Carvalho Chehab , "Jonathan Corbet" , "Mauro Carvalho Chehab" , linux-kernel@vger.kernel.org Subject: [PATCH v2 24/39] scripts: sphinx-pre-install: convert is_optional to a class Date: Tue, 12 Aug 2025 17:52:41 +0200 Message-ID: <42290a24f3b1dbea9ebe19747cf5622bb2f2cf5c.1754992972.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.50.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab Content-Type: text/plain; charset="utf-8" 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. Signed-off-by: Mauro Carvalho Chehab --- scripts/sphinx-pre-install.py | 192 +++++++++++++++++++++++----------- 1 file changed, 130 insertions(+), 62 deletions(-) diff --git a/scripts/sphinx-pre-install.py b/scripts/sphinx-pre-install.py index a5c777e529ec..0963da21c27b 100755 --- a/scripts/sphinx-pre-install.py +++ b/scripts/sphinx-pre-install.py @@ -32,6 +32,53 @@ RECOMMENDED_VERSION =3D parse_version("3.4.3") MIN_PYTHON_VERSION =3D parse_version("3.7") =20 =20 +class DepType: + + # Internal types of dependencies. + _SYS_TYPE =3D 0 + _PHY_TYPE =3D 1 + _PDF_TYPE =3D 2 + + # Let's define keys as a tuple with the type and mandatory/optional. + # This way, checking for optional or type is easy. + + SYSTEM_MANDATORY =3D (_SYS_TYPE, True) + PYTHON_MANDATORY =3D (_PHY_TYPE, True) + PDF_MANDATORY =3D (_PDF_TYPE, True) + + # Currently we're not using all optional types, but let's keep all + # combinations here, as we may end needing them in the future. Also, + # it allows a name() function that handles all possibilities. + SYSTEM_OPTIONAL =3D (_SYS_TYPE, False) + PYTHON_OPTIONAL =3D (_PHY_TYPE, False) + PDF_OPTIONAL =3D (_PDF_TYPE, True) + + @staticmethod + def name(dtype): + if dtype[0] =3D=3D DepType._SYS_TYPE: + msg =3D "build" + elif dtype[0] =3D=3D DepType._PHY_TYPE: + msg =3D "Python" + else: + msg =3D "PDF" + + if dtype[1]: + return f"ERROR: {msg} mandatory deps missing" + else: + out =3D f"Warning: {msg} optional deps missing" + + @staticmethod + def is_optional(dtype): + return not dtype[1] + + @staticmethod + def is_pdf(dtype): + if (dtype[0] =3D=3D DepType._PDF_TYPE): + return True + + return False + + class SphinxDependencyChecker: # List of required texlive packages on Fedora and OpenSuse texlive =3D { @@ -223,56 +270,68 @@ class SphinxDependencyChecker: # Methods to check if a feature exists # =20 - # Note: is_optional has 3 states: - # - 0: mandatory - # - 1: optional, but nice to have - # - 2: LaTeX optional - pdf builds without it, but may have visual i= mpact - def check_missing(self, progs): - for prog, is_optional in sorted(self.missing.items()): + run =3D {} + + for prog, dtype in sorted(self.missing.items()): # At least on some LTS distros like CentOS 7, texlive doesn't # provide all packages we need. When such distros are # detected, we have to disable PDF output. # # So, we need to ignore the packages that distros would # need for LaTeX to work - if is_optional =3D=3D 2 and not self.pdf: + if DepType.is_pdf(dtype) and not self.pdf: self.optional -=3D 1 continue =20 + if not dtype in run: + run[dtype] =3D [] + + run[dtype].append(prog) + + output_msg =3D "" + + for dtype in sorted(run.keys()): + progs =3D " ".join(run[dtype]) + if self.verbose_warn_install: - if is_optional: - print(f'Warning: better to also install "{prog}".') - else: - print(f'ERROR: please install "{prog}", otherwise, bui= ld won\'t work.') + try: + name =3D DepType.name(dtype) + output_msg +=3D f'{name}:\t{progs}\n' + except KeyError: + raise KeyError(f"ERROR!!!: invalid dtype for {progs}: = {dtype}") =20 - self.install +=3D " " + progs.get(prog, prog) + self.install +=3D " " + progs + + if output_msg: + print(f"\n{output_msg}\n") =20 self.install =3D self.install.lstrip() =20 - def add_package(self, package, is_optional): - self.missing[package] =3D is_optional + def add_package(self, package, dtype): + is_optional =3D DepType.is_optional(dtype) + self.missing[package] =3D dtype if is_optional: self.optional +=3D 1 else: self.need +=3D 1 =20 - def check_missing_file(self, files, package, is_optional): + def check_missing_file(self, files, package, dtype): for f in files: if os.path.exists(f): return - self.add_package(package, is_optional) + self.add_package(package, dtype) =20 - def check_program(self, prog, is_optional): + def check_program(self, prog, dtype): found =3D self.which(prog) if found: return found =20 - self.add_package(prog, is_optional) + self.add_package(prog, dtype) =20 return None =20 - def check_perl_module(self, prog, is_optional): + def check_perl_module(self, prog, dtype): # While testing with lxc download template, one of the # distros (Oracle) didn't have perl - nor even an option to install # before installing oraclelinux-release-el9 package. @@ -281,46 +340,52 @@ class SphinxDependencyChecker: # add it as a mandatory package, as some parts of the doc builder # needs it. if not self.which("perl"): - self.add_package("perl", 0) - self.add_package(prog, is_optional) + self.add_package("perl", DepType.SYSTEM_MANDATORY) + self.add_package(prog, dtype) return =20 try: self.run(["perl", f"-M{prog}", "-e", "1"], check=3DTrue) except subprocess.CalledProcessError: - self.add_package(prog, is_optional) + self.add_package(prog, dtype) =20 - def check_python_module(self, module, is_optional): - # FIXME: is it needed at the Python version? Maybe due to venv? - if not self.python_cmd: - return + def check_python_module(self, module, is_optional=3DFalse): + if is_optional: + dtype =3D DepType.PYTHON_OPTIONAL + else: + dtype =3D DepType.PYTHON_MANDATORY =20 try: self.run([self.python_cmd, "-c", f"import {module}"], check=3D= True) except subprocess.CalledProcessError: - self.add_package(module, is_optional) + self.add_package(module, dtype) =20 - def check_rpm_missing(self, pkgs, is_optional): + def check_rpm_missing(self, pkgs, dtype): for prog in pkgs: try: self.run(["rpm", "-q", prog], check=3DTrue) except subprocess.CalledProcessError: - self.add_package(prog, is_optional) + self.add_package(prog, dtype) =20 - def check_pacman_missing(self, pkgs, is_optional): + def check_pacman_missing(self, pkgs, dtype): for prog in pkgs: try: self.run(["pacman", "-Q", prog], check=3DTrue) except subprocess.CalledProcessError: - self.add_package(prog, is_optional) + self.add_package(prog, dtype) + + def check_missing_tex(self, is_optional=3DFalse): + if is_optional: + dtype =3D DepType.PDF_OPTIONAL + else: + dtype =3D DepType.PDF_MANDATORY =20 - def check_missing_tex(self, is_optional): kpsewhich =3D self.which("kpsewhich") for prog, package in self.texlive.items(): =20 # If kpsewhich is not there, just add it to deps if not kpsewhich: - self.add_package(package, is_optional) + self.add_package(package, dtype) continue =20 # Check if the package is needed @@ -331,11 +396,11 @@ class SphinxDependencyChecker: =20 # Didn't find. Add it if not result.stdout.strip(): - self.add_package(package, is_optional) + self.add_package(package, dtype) =20 except subprocess.CalledProcessError: # kpsewhich returned an error. Add it, just in case - self.add_package(package, is_optional) + self.add_package(package, dtype) =20 def get_sphinx_fname(self): if "SPHINXBUILD" in os.environ: @@ -446,9 +511,9 @@ class SphinxDependencyChecker: } =20 for package, files in pdf_pkgs.items(): - self.check_missing_file(files, package, 2) + self.check_missing_file(files, package, DepType.PDF_MANDAT= ORY) =20 - self.check_program("dvipng", 2) + self.check_program("dvipng", DepType.PDF_MANDATORY) =20 self.check_missing(progs) =20 @@ -518,7 +583,7 @@ class SphinxDependencyChecker: # RHEL 8 uses Python 3.6, which is not compatible with # the build system anymore. Suggest Python 3.11 if rel =3D=3D 8: - self.add_package("python39", 0) + self.add_package("python39", DepType.SYSTEM_MANDATORY) self.recommend_python =3D True =20 if self.first_hint: @@ -540,13 +605,13 @@ class SphinxDependencyChecker: "/usr/share/fonts/google-noto-sans-cjk-fonts/NotoSansCJK-R= egular.ttc", ] =20 - self.check_missing_file(pdf_pkgs, noto_sans_redhat, 2) + self.check_missing_file(pdf_pkgs, noto_sans_redhat, DepType.PD= F_MANDATORY) =20 if not old: - self.check_rpm_missing(fedora26_opt_pkgs, 2) - self.check_rpm_missing(fedora_tex_pkgs, 2) + self.check_rpm_missing(fedora26_opt_pkgs, DepType.PDF_MAND= ATORY) + self.check_rpm_missing(fedora_tex_pkgs, DepType.PDF_MANDAT= ORY) =20 - self.check_missing_tex(2) + self.check_missing_tex() =20 self.check_missing(progs) =20 @@ -601,7 +666,7 @@ class SphinxDependencyChecker: if rel =3D=3D 15: if not self.which(self.python_cmd): self.recommend_python =3D True - self.add_package(self.python_cmd, 0) + self.add_package(self.python_cmd, DepType.SYSTEM_MANDA= TORY) =20 progs.update({ "python-sphinx": "python311-Sphinx", @@ -623,9 +688,9 @@ class SphinxDependencyChecker: # "Noto Sans CJK SC" on openSUSE =20 if self.pdf: - self.check_rpm_missing(suse_tex_pkgs, 2) + self.check_rpm_missing(suse_tex_pkgs, DepType.PDF_MANDATORY) if self.pdf: - self.check_missing_tex(2) + self.check_missing_tex() self.check_missing(progs) =20 if not self.need and not self.optional: @@ -672,8 +737,8 @@ class SphinxDependencyChecker: "/usr/share/fonts/TTF/NotoSans-Regular.ttf", ] =20 - self.check_missing_file(pdf_pkgs, noto_sans, 2) - self.check_rpm_missing(tex_pkgs, 2) + self.check_missing_file(pdf_pkgs, noto_sans, DepType.PDF_MANDA= TORY) + self.check_rpm_missing(tex_pkgs, DepType.PDF_MANDATORY) =20 self.check_missing(progs) =20 @@ -701,7 +766,7 @@ class SphinxDependencyChecker: ] =20 if self.pdf: - self.check_pacman_missing(archlinux_tex_pkgs, 2) + self.check_pacman_missing(archlinux_tex_pkgs, DepType.PDF_MAND= ATORY) =20 self.check_missing_file( ["/usr/share/fonts/noto-cjk/NotoSansCJK-Regular.ttc"], @@ -739,7 +804,7 @@ class SphinxDependencyChecker: ], } for package, files in pdf_pkgs.items(): - self.check_missing_file(files, package, 2) + self.check_missing_file(files, package, DepType.PDF_MANDAT= ORY) =20 self.check_missing(progs) =20 @@ -878,7 +943,7 @@ class SphinxDependencyChecker: # progs =3D {"sphinx-build": "sphinx"} if self.pdf: - self.check_missing_tex(2) + self.check_missing_tex() =20 self.check_missing(progs) =20 @@ -990,7 +1055,7 @@ class SphinxDependencyChecker: old_verbose =3D self.verbose_warn_install self.verbose_warn_install =3D 0 =20 - self.add_package("python-sphinx", 0) + self.add_package("python-sphinx", DepType.PYTHON_MANDATORY) =20 self.check_distros() =20 @@ -1010,6 +1075,7 @@ class SphinxDependencyChecker: "Please upgrade it and re-run.\n") return =20 + # Version is OK. Nothing to do. if self.cur_version !=3D (0, 0, 0) and self.cur_version >=3D RECOM= MENDED_VERSION: return @@ -1128,21 +1194,23 @@ class SphinxDependencyChecker: =20 else: virtualenv_cmd =3D f"{self.python_cmd} -m venv" - self.check_python_module("ensurepip", 0) + self.check_python_module("ensurepip") =20 # Check for needed programs/tools - self.check_perl_module("Pod::Usage", 0) - self.check_python_module("yaml", 0) - self.check_program("make", 0) - self.check_program("gcc", 0) - self.check_program("dot", 1) - self.check_program("convert", 1) + self.check_perl_module("Pod::Usage", DepType.SYSTEM_MANDATORY) + + self.check_program("make", DepType.SYSTEM_MANDATORY) + self.check_program("gcc", DepType.SYSTEM_MANDATORY) + + self.check_program("dot", DepType.SYSTEM_OPTIONAL) + self.check_program("convert", DepType.SYSTEM_OPTIONAL) + + self.check_python_module("yaml") =20 if self.pdf: - # Extra PDF files - should use 2 for LaTeX is_optional - self.check_program("xelatex", 2) - self.check_program("rsvg-convert", 2) - self.check_program("latexmk", 2) + self.check_program("xelatex", DepType.PDF_MANDATORY) + self.check_program("rsvg-convert", DepType.PDF_MANDATORY) + self.check_program("latexmk", DepType.PDF_MANDATORY) =20 # Do distro-specific checks and output distro-install commands self.check_distros() --=20 2.50.1