From nobody Tue Oct 7 14:56:31 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 52B7A2E7174; Wed, 9 Jul 2025 13:52:22 +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=1752069142; cv=none; b=JiOhKv5z+FzPNEHPs5mZi4AhGTaLuqZTKSzIZb30oB363tFzi/tlRG+N5OC6sco1YwI8HpjTrwWDQ9R3X7aV1C2lGYI0IJJ5xeB322Z+4CzfiVdN1qZIuR25muln9HSnCmPPREVSqj9SBLLEeATXw+amZb6vMSkHZaLSSU4iIYI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1752069142; c=relaxed/simple; bh=RueffcvRIDBMi87r9z1UtD/9fAlr6jNpZ48zD4mdxEU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=btXqD9fAz/15uH/kXHJFtLt1tS0nol+LmjGwdj0ZpY988/Al5HXODx5pLWTEXkVCSR1mQwvmGImpmDRnHhlAiIsQtuGYR4O+RCT3YnezL/qX2+x8c7M++qkLOAqLMSc+9vxkuxSjhKNyId2BDAxQ5gba7GzzzTuQXpoyzFR0Iq0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Os5ODMwm; 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="Os5ODMwm" Received: by smtp.kernel.org (Postfix) with ESMTPSA id BE659C2BCAF; Wed, 9 Jul 2025 13:52:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1752069142; bh=RueffcvRIDBMi87r9z1UtD/9fAlr6jNpZ48zD4mdxEU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Os5ODMwmRMfr1p9vKuQy8CQir2xKw3QFxr8Uzjkc465O5171W3mLLREHt2U1towi4 qooZjWT5BMgqaKp1+aBmfFS4balt+ljGSx3XyAOmtUlr8hR/xBiYZBBAOsbVBfq+Xu dW2sgeWoBLSWqVMVVLZ7bPQLJ9+M9tEwrjfmQ69qDzV7NNAtqZF/5dIMH2N9ytx7NZ A6b5tHge5xw11uhNZ5u2UIOCpqlxL4f58qhaBpf/pqLzDWeYYgdZyM9zYnRfh7x+bm emtKv3ha3oZXRtFYJxPC3WOJPOZgXKxFVh7YAlmmsQ1gWI+mMACCjtIAyvijK0vSuw a1mfbmEdT6WBQ== Received: from mchehab by mail.kernel.org with local (Exim 4.98.2) (envelope-from ) id 1uZVDd-00000000EDM-2pom; Wed, 09 Jul 2025 15:52:17 +0200 From: Mauro Carvalho Chehab To: Linux Doc Mailing List , Jonathan Corbet Cc: Mauro Carvalho Chehab , "Akira Yokosawa" , Mauro Carvalho Chehab , linux-kernel@vger.kernel.org Subject: [PATCH v2 26/39] scripts: sphinx-pre-install: move missing logic to a separate class Date: Wed, 9 Jul 2025 15:51:58 +0200 Message-ID: X-Mailer: git-send-email 2.49.0 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" Better manage dependencies by placing them on a distro-independent class. Signed-off-by: Mauro Carvalho Chehab --- scripts/sphinx-pre-install.py | 251 +++++++++++++++++++--------------- 1 file changed, 138 insertions(+), 113 deletions(-) diff --git a/scripts/sphinx-pre-install.py b/scripts/sphinx-pre-install.py index 592223fa686f..47dce1fcddfb 100755 --- a/scripts/sphinx-pre-install.py +++ b/scripts/sphinx-pre-install.py @@ -32,7 +32,7 @@ RECOMMENDED_VERSION =3D parse_version("3.4.3") MIN_PYTHON_VERSION =3D parse_version("3.7") =20 =20 -class DepType: +class DepManager: =20 # Internal types of dependencies. _SYS_TYPE =3D 0 @@ -53,11 +53,18 @@ class DepType: PYTHON_OPTIONAL =3D (_PHY_TYPE, False) PDF_OPTIONAL =3D (_PDF_TYPE, True) =20 + def __init__(self, pdf): + self.missing =3D {} + self.run =3D {} + self.need =3D 0 + self.optional =3D 0 + self.pdf =3D pdf + @staticmethod def name(dtype): - if dtype[0] =3D=3D DepType._SYS_TYPE: + if dtype[0] =3D=3D DepManager._SYS_TYPE: msg =3D "build" - elif dtype[0] =3D=3D DepType._PHY_TYPE: + elif dtype[0] =3D=3D DepManager._PHY_TYPE: msg =3D "Python" else: msg =3D "PDF" @@ -73,11 +80,75 @@ class DepType: =20 @staticmethod def is_pdf(dtype): - if (dtype[0] =3D=3D DepType._PDF_TYPE): + if (dtype[0] =3D=3D DepManager._PDF_TYPE): return True =20 return False =20 + def add_package(self, package, dtype): + is_optional =3D DepManager.is_optional(dtype) + self.missing[package] =3D dtype + if is_optional: + self.optional +=3D 1 + else: + self.need +=3D 1 + + def del_package(self, package): + if package in self.missing: + del self.missing[package] + + def clear_deps(self): + """ + Clear dependencies without changing needed/optional. + + This is an ackward way to have a separate section to recommend + a package after system main dependencies. + + TODO: rework the logic to prevent needing it + """ + + self.missing =3D {} + + def check_missing(self, progs): + self.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 DepManager.is_pdf(dtype) and not self.pdf: + self.optional -=3D 1 + continue + + if not dtype in self.run: + self.run[dtype] =3D [] + + self.run[dtype].append(progs.get(prog, prog)) + + install =3D [] + for dtype in self.run.keys(): + install +=3D self.run[dtype] + + return " ".join(sorted(set(install))) + + def warn_install(self): + + output_msg =3D "" + + for dtype in sorted(self.run.keys()): + progs =3D " ".join(sorted(set(self.run[dtype]))) + + try: + name =3D DepManager.name(dtype) + output_msg +=3D f'{name}:\t{progs}\n' + except KeyError: + raise KeyError(f"ERROR!!!: invalid dtype for {progs}: {dty= pe}") + + if output_msg: + print(f"\n{output_msg}\n") =20 class SphinxDependencyChecker: # List of required texlive packages on Fedora and OpenSuse @@ -120,10 +191,8 @@ class SphinxDependencyChecker: self.virtualenv =3D args.virtualenv self.version_check =3D args.version_check =20 - self.missing =3D {} + self.deps =3D DepManager(self.pdf) =20 - self.need =3D 0 - self.optional =3D 0 self.need_symlink =3D 0 self.need_sphinx =3D 0 self.need_pip =3D 0 @@ -270,64 +339,18 @@ class SphinxDependencyChecker: # Methods to check if a feature exists # =20 - def check_missing(self, progs): - 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 DepType.is_pdf(dtype) and not self.pdf: - self.optional -=3D 1 - continue - - 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: - 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}") - - self.install +=3D " " + progs - - if output_msg: - print(f"\n{output_msg}\n") - - self.install =3D self.install.lstrip() - - 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 - def check_missing_file(self, files, package, dtype): for f in files: if os.path.exists(f): return - self.add_package(package, dtype) + self.deps.add_package(package, dtype) =20 def check_program(self, prog, dtype): found =3D self.which(prog) if found: return found =20 - self.add_package(prog, dtype) + self.deps.add_package(prog, dtype) =20 return None =20 @@ -340,52 +363,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", DepType.SYSTEM_MANDATORY) - self.add_package(prog, dtype) + self.deps.add_package("perl", DepManager.SYSTEM_MANDATORY) + self.deps.add_package(prog, dtype) return =20 try: self.run(["perl", f"-M{prog}", "-e", "1"], check=3DTrue) except subprocess.CalledProcessError: - self.add_package(prog, dtype) + self.deps.add_package(prog, dtype) =20 def check_python_module(self, module, is_optional=3DFalse): if is_optional: - dtype =3D DepType.PYTHON_OPTIONAL + dtype =3D DepManager.PYTHON_OPTIONAL else: - dtype =3D DepType.PYTHON_MANDATORY + dtype =3D DepManager.PYTHON_MANDATORY =20 try: self.run([self.python_cmd, "-c", f"import {module}"], check=3D= True) except subprocess.CalledProcessError: - self.add_package(module, dtype) + self.deps.add_package(module, dtype) =20 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, dtype) + self.deps.add_package(prog, dtype) =20 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, dtype) + self.deps.add_package(prog, dtype) =20 def check_missing_tex(self, is_optional=3DFalse): if is_optional: - dtype =3D DepType.PDF_OPTIONAL + dtype =3D DepManager.PDF_OPTIONAL else: - dtype =3D DepType.PDF_MANDATORY + dtype =3D DepManager.PDF_MANDATORY =20 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, dtype) + self.deps.add_package(package, dtype) continue =20 # Check if the package is needed @@ -396,11 +419,11 @@ class SphinxDependencyChecker: =20 # Didn't find. Add it if not result.stdout.strip(): - self.add_package(package, dtype) + self.deps.add_package(package, dtype) =20 except subprocess.CalledProcessError: # kpsewhich returned an error. Add it, just in case - self.add_package(package, dtype) + self.deps.add_package(package, dtype) =20 def get_sphinx_fname(self): if "SPHINXBUILD" in os.environ: @@ -478,6 +501,17 @@ class SphinxDependencyChecker: return f.read().strip() return "" =20 + def check_missing(self, progs): + self.install +=3D self.deps.check_missing(progs) + if self.verbose_warn_install: + self.deps.warn_install() + + if not self.deps.need and not self.deps.optional: + return False + + return True + + # # Distro-specific hints methods # @@ -511,13 +545,11 @@ class SphinxDependencyChecker: } =20 for package, files in pdf_pkgs.items(): - self.check_missing_file(files, package, DepType.PDF_MANDAT= ORY) + self.check_missing_file(files, package, DepManager.PDF_MAN= DATORY) =20 - self.check_program("dvipng", DepType.PDF_MANDATORY) + self.check_program("dvipng", DepManager.PDF_MANDATORY) =20 - self.check_missing(progs) - - if not self.need and not self.optional: + if self.check_missing(progs): return =20 if self.verbose_warn_install: @@ -575,7 +607,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", DepType.SYSTEM_MANDATORY) + self.deps.add_package("python39", DepManager.SYSTEM_MANDAT= ORY) self.recommend_python =3D True =20 if self.first_hint: @@ -597,22 +629,18 @@ class SphinxDependencyChecker: "/usr/share/fonts/google-noto-sans-cjk-fonts/NotoSansCJK-R= egular.ttc", ] =20 - self.check_missing_file(pdf_pkgs, noto_sans_redhat, DepType.PD= F_MANDATORY) + self.check_missing_file(pdf_pkgs, noto_sans_redhat, DepManager= .PDF_MANDATORY) =20 - self.check_rpm_missing(fedora_tex_pkgs, DepType.PDF_MANDATORY) + self.check_rpm_missing(fedora_tex_pkgs, DepManager.PDF_MANDATO= RY) =20 - self.check_missing_tex(DepType.PDF_MANDATORY) + self.check_missing_tex(DepManager.PDF_MANDATORY) =20 # There's no texlive-ctex on RHEL 8 repositories. This will # likely affect CJK pdf build only. if not fedora and rel =3D=3D 8: - if "texlive-ctex" in self.missing: - del self.missing["texlive-ctex"] + self.deps.del_package("texlive-ctex") =20 - - self.check_missing(progs) - - if not self.need and not self.optional: + if self.check_missing(progs): return =20 if self.verbose_warn_install: @@ -659,7 +687,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, DepType.SYSTEM_MANDA= TORY) + self.deps.add_package(self.python_cmd, DepManager.SYST= EM_MANDATORY) =20 progs.update({ "python-sphinx": "python311-Sphinx", @@ -681,12 +709,11 @@ class SphinxDependencyChecker: # "Noto Sans CJK SC" on openSUSE =20 if self.pdf: - self.check_rpm_missing(suse_tex_pkgs, DepType.PDF_MANDATORY) + self.check_rpm_missing(suse_tex_pkgs, DepManager.PDF_MANDATORY) if self.pdf: self.check_missing_tex() - self.check_missing(progs) =20 - if not self.need and not self.optional: + if self.check_missing(progs): return =20 if self.verbose_warn_install: @@ -730,13 +757,12 @@ class SphinxDependencyChecker: "/usr/share/fonts/TTF/NotoSans-Regular.ttf", ] =20 - self.check_missing_file(pdf_pkgs, noto_sans, DepType.PDF_MANDA= TORY) - self.check_rpm_missing(tex_pkgs, DepType.PDF_MANDATORY) + self.check_missing_file(pdf_pkgs, noto_sans, DepManager.PDF_MA= NDATORY) + self.check_rpm_missing(tex_pkgs, DepManager.PDF_MANDATORY) =20 - self.check_missing(progs) - - if not self.need and not self.optional: + if self.check_missing(progs): return + if self.verbose_warn_install: print("You should run:") print(f"\n\tsudo {packager_cmd} {self.install}") @@ -759,7 +785,7 @@ class SphinxDependencyChecker: ] =20 if self.pdf: - self.check_pacman_missing(archlinux_tex_pkgs, DepType.PDF_MAND= ATORY) + self.check_pacman_missing(archlinux_tex_pkgs, DepManager.PDF_M= ANDATORY) =20 self.check_missing_file( ["/usr/share/fonts/noto-cjk/NotoSansCJK-Regular.ttc"], @@ -767,10 +793,9 @@ class SphinxDependencyChecker: 2, ) =20 - self.check_missing(progs) - - if not self.need and not self.optional: + if self.check_missing(progs): return + if self.verbose_warn_install: print("You should run:") print(f"\n\tsudo pacman -S {self.install}") @@ -797,11 +822,9 @@ class SphinxDependencyChecker: ], } for package, files in pdf_pkgs.items(): - self.check_missing_file(files, package, DepType.PDF_MANDAT= ORY) + self.check_missing_file(files, package, DepManager.PDF_MAN= DATORY) =20 - self.check_missing(progs) - - if not self.need and not self.optional: + if self.check_missing(progs): return =20 if self.verbose_warn_install: @@ -1039,16 +1062,18 @@ class SphinxDependencyChecker: =20 print("\n2) As a package with:") =20 - old_need =3D self.need - old_optional =3D self.optional - self.missing =3D {} + old_need =3D self.deps.need + old_optional =3D self.deps.optional + self.pdf =3D False self.optional =3D 0 self.install =3D "" old_verbose =3D self.verbose_warn_install self.verbose_warn_install =3D 0 =20 - self.add_package("python-sphinx", DepType.PYTHON_MANDATORY) + self.deps.clear_deps() + + self.deps.add_package("python-sphinx", DepManager.PYTHON_MANDATORY) =20 self.check_distros() =20 @@ -1111,7 +1136,7 @@ class SphinxDependencyChecker: print("\n") else: if self.need_sphinx: - self.need +=3D 1 + self.deps.need +=3D 1 =20 # Suggest newer versions if current ones are too old if self.latest_avail_ver and self.latest_avail_ver >=3D self.min_v= ersion: @@ -1190,20 +1215,20 @@ class SphinxDependencyChecker: self.check_python_module("ensurepip") =20 # Check for needed programs/tools - self.check_perl_module("Pod::Usage", DepType.SYSTEM_MANDATORY) + self.check_perl_module("Pod::Usage", DepManager.SYSTEM_MANDATORY) =20 - self.check_program("make", DepType.SYSTEM_MANDATORY) - self.check_program("gcc", DepType.SYSTEM_MANDATORY) + self.check_program("make", DepManager.SYSTEM_MANDATORY) + self.check_program("gcc", DepManager.SYSTEM_MANDATORY) =20 - self.check_program("dot", DepType.SYSTEM_OPTIONAL) - self.check_program("convert", DepType.SYSTEM_OPTIONAL) + self.check_program("dot", DepManager.SYSTEM_OPTIONAL) + self.check_program("convert", DepManager.SYSTEM_OPTIONAL) =20 self.check_python_module("yaml") =20 if self.pdf: - self.check_program("xelatex", DepType.PDF_MANDATORY) - self.check_program("rsvg-convert", DepType.PDF_MANDATORY) - self.check_program("latexmk", DepType.PDF_MANDATORY) + self.check_program("xelatex", DepManager.PDF_MANDATORY) + self.check_program("rsvg-convert", DepManager.PDF_MANDATORY) + self.check_program("latexmk", DepManager.PDF_MANDATORY) =20 # Do distro-specific checks and output distro-install commands self.check_distros() --=20 2.49.0