1*abd61d1fSMauro Carvalho Chehab#!/usr/bin/env python3 2*abd61d1fSMauro Carvalho Chehab# SPDX-License-Identifier: GPL-2.0-or-later 3*abd61d1fSMauro Carvalho Chehab# Copyright (c) 2017-2025 Mauro Carvalho Chehab <mchehab+huawei@kernel.org> 4*abd61d1fSMauro Carvalho Chehab# 5*abd61d1fSMauro Carvalho Chehab# pylint: disable=C0103,C0114,C0115,C0116,C0301,C0302 6*abd61d1fSMauro Carvalho Chehab# pylint: disable=R0902,R0904,R0911,R0912,R0914,R0915,R1705,R1710,E1121 7*abd61d1fSMauro Carvalho Chehab 8*abd61d1fSMauro Carvalho Chehab# Note: this script requires at least Python 3.6 to run. 9*abd61d1fSMauro Carvalho Chehab# Don't add changes not compatible with it, it is meant to report 10*abd61d1fSMauro Carvalho Chehab# incompatible python versions. 11*abd61d1fSMauro Carvalho Chehab 12*abd61d1fSMauro Carvalho Chehab""" 13*abd61d1fSMauro Carvalho ChehabDependency checker for Sphinx documentation Kernel build. 14*abd61d1fSMauro Carvalho Chehab 15*abd61d1fSMauro Carvalho ChehabThis module provides tools to check for all required dependencies needed to 16*abd61d1fSMauro Carvalho Chehabbuild documentation using Sphinx, including system packages, Python modules 17*abd61d1fSMauro Carvalho Chehaband LaTeX packages for PDF generation. 18*abd61d1fSMauro Carvalho Chehab 19*abd61d1fSMauro Carvalho ChehabIt detect packages for a subset of Linux distributions used by Kernel 20*abd61d1fSMauro Carvalho Chehabmaintainers, showing hints and missing dependencies. 21*abd61d1fSMauro Carvalho Chehab 22*abd61d1fSMauro Carvalho ChehabThe main class SphinxDependencyChecker handles the dependency checking logic 23*abd61d1fSMauro Carvalho Chehaband provides recommendations for installing missing packages. It supports both 24*abd61d1fSMauro Carvalho Chehabsystem package installations and Python virtual environments. By default, 25*abd61d1fSMauro Carvalho Chehabsystem pacage install is recommended. 26*abd61d1fSMauro Carvalho Chehab""" 27*abd61d1fSMauro Carvalho Chehab 28*abd61d1fSMauro Carvalho Chehabimport argparse 29*abd61d1fSMauro Carvalho Chehabimport os 30*abd61d1fSMauro Carvalho Chehabimport re 31*abd61d1fSMauro Carvalho Chehabimport subprocess 32*abd61d1fSMauro Carvalho Chehabimport sys 33*abd61d1fSMauro Carvalho Chehabfrom glob import glob 34*abd61d1fSMauro Carvalho Chehab 35*abd61d1fSMauro Carvalho Chehab 36*abd61d1fSMauro Carvalho Chehabdef parse_version(version): 37*abd61d1fSMauro Carvalho Chehab """Convert a major.minor.patch version into a tuple""" 38*abd61d1fSMauro Carvalho Chehab return tuple(int(x) for x in version.split(".")) 39*abd61d1fSMauro Carvalho Chehab 40*abd61d1fSMauro Carvalho Chehab 41*abd61d1fSMauro Carvalho Chehabdef ver_str(version): 42*abd61d1fSMauro Carvalho Chehab """Returns a version tuple as major.minor.patch""" 43*abd61d1fSMauro Carvalho Chehab 44*abd61d1fSMauro Carvalho Chehab return ".".join([str(x) for x in version]) 45*abd61d1fSMauro Carvalho Chehab 46*abd61d1fSMauro Carvalho Chehab 47*abd61d1fSMauro Carvalho ChehabRECOMMENDED_VERSION = parse_version("3.4.3") 48*abd61d1fSMauro Carvalho ChehabMIN_PYTHON_VERSION = parse_version("3.7") 49*abd61d1fSMauro Carvalho Chehab 50*abd61d1fSMauro Carvalho Chehab 51*abd61d1fSMauro Carvalho Chehabclass DepManager: 52*abd61d1fSMauro Carvalho Chehab """ 53*abd61d1fSMauro Carvalho Chehab Manage package dependencies. There are three types of dependencies: 54*abd61d1fSMauro Carvalho Chehab 55*abd61d1fSMauro Carvalho Chehab - System: dependencies required for docs build; 56*abd61d1fSMauro Carvalho Chehab - Python: python dependencies for a native distro Sphinx install; 57*abd61d1fSMauro Carvalho Chehab - PDF: dependencies needed by PDF builds. 58*abd61d1fSMauro Carvalho Chehab 59*abd61d1fSMauro Carvalho Chehab Each dependency can be mandatory or optional. Not installing an optional 60*abd61d1fSMauro Carvalho Chehab dependency won't break the build, but will cause degradation at the 61*abd61d1fSMauro Carvalho Chehab docs output. 62*abd61d1fSMauro Carvalho Chehab """ 63*abd61d1fSMauro Carvalho Chehab 64*abd61d1fSMauro Carvalho Chehab # Internal types of dependencies. Don't use them outside DepManager class. 65*abd61d1fSMauro Carvalho Chehab _SYS_TYPE = 0 66*abd61d1fSMauro Carvalho Chehab _PHY_TYPE = 1 67*abd61d1fSMauro Carvalho Chehab _PDF_TYPE = 2 68*abd61d1fSMauro Carvalho Chehab 69*abd61d1fSMauro Carvalho Chehab # Dependencies visible outside the class. 70*abd61d1fSMauro Carvalho Chehab # The keys are tuple with: (type, is_mandatory flag). 71*abd61d1fSMauro Carvalho Chehab # 72*abd61d1fSMauro Carvalho Chehab # Currently we're not using all optional dep types. Yet, we'll keep all 73*abd61d1fSMauro Carvalho Chehab # possible combinations here. They're not many, and that makes easier 74*abd61d1fSMauro Carvalho Chehab # if later needed and for the name() method below 75*abd61d1fSMauro Carvalho Chehab 76*abd61d1fSMauro Carvalho Chehab SYSTEM_MANDATORY = (_SYS_TYPE, True) 77*abd61d1fSMauro Carvalho Chehab PYTHON_MANDATORY = (_PHY_TYPE, True) 78*abd61d1fSMauro Carvalho Chehab PDF_MANDATORY = (_PDF_TYPE, True) 79*abd61d1fSMauro Carvalho Chehab 80*abd61d1fSMauro Carvalho Chehab SYSTEM_OPTIONAL = (_SYS_TYPE, False) 81*abd61d1fSMauro Carvalho Chehab PYTHON_OPTIONAL = (_PHY_TYPE, False) 82*abd61d1fSMauro Carvalho Chehab PDF_OPTIONAL = (_PDF_TYPE, True) 83*abd61d1fSMauro Carvalho Chehab 84*abd61d1fSMauro Carvalho Chehab def __init__(self, pdf): 85*abd61d1fSMauro Carvalho Chehab """ 86*abd61d1fSMauro Carvalho Chehab Initialize internal vars: 87*abd61d1fSMauro Carvalho Chehab 88*abd61d1fSMauro Carvalho Chehab - missing: missing dependencies list, containing a distro-independent 89*abd61d1fSMauro Carvalho Chehab name for a missing dependency and its type. 90*abd61d1fSMauro Carvalho Chehab - missing_pkg: ancillary dict containing missing dependencies in 91*abd61d1fSMauro Carvalho Chehab distro namespace, organized by type. 92*abd61d1fSMauro Carvalho Chehab - need: total number of needed dependencies. Never cleaned. 93*abd61d1fSMauro Carvalho Chehab - optional: total number of optional dependencies. Never cleaned. 94*abd61d1fSMauro Carvalho Chehab - pdf: Is PDF support enabled? 95*abd61d1fSMauro Carvalho Chehab """ 96*abd61d1fSMauro Carvalho Chehab self.missing = {} 97*abd61d1fSMauro Carvalho Chehab self.missing_pkg = {} 98*abd61d1fSMauro Carvalho Chehab self.need = 0 99*abd61d1fSMauro Carvalho Chehab self.optional = 0 100*abd61d1fSMauro Carvalho Chehab self.pdf = pdf 101*abd61d1fSMauro Carvalho Chehab 102*abd61d1fSMauro Carvalho Chehab @staticmethod 103*abd61d1fSMauro Carvalho Chehab def name(dtype): 104*abd61d1fSMauro Carvalho Chehab """ 105*abd61d1fSMauro Carvalho Chehab Ancillary routine to output a warn/error message reporting 106*abd61d1fSMauro Carvalho Chehab missing dependencies. 107*abd61d1fSMauro Carvalho Chehab """ 108*abd61d1fSMauro Carvalho Chehab if dtype[0] == DepManager._SYS_TYPE: 109*abd61d1fSMauro Carvalho Chehab msg = "build" 110*abd61d1fSMauro Carvalho Chehab elif dtype[0] == DepManager._PHY_TYPE: 111*abd61d1fSMauro Carvalho Chehab msg = "Python" 112*abd61d1fSMauro Carvalho Chehab else: 113*abd61d1fSMauro Carvalho Chehab msg = "PDF" 114*abd61d1fSMauro Carvalho Chehab 115*abd61d1fSMauro Carvalho Chehab if dtype[1]: 116*abd61d1fSMauro Carvalho Chehab return f"ERROR: {msg} mandatory deps missing" 117*abd61d1fSMauro Carvalho Chehab else: 118*abd61d1fSMauro Carvalho Chehab return f"Warning: {msg} optional deps missing" 119*abd61d1fSMauro Carvalho Chehab 120*abd61d1fSMauro Carvalho Chehab @staticmethod 121*abd61d1fSMauro Carvalho Chehab def is_optional(dtype): 122*abd61d1fSMauro Carvalho Chehab """Ancillary routine to report if a dependency is optional""" 123*abd61d1fSMauro Carvalho Chehab return not dtype[1] 124*abd61d1fSMauro Carvalho Chehab 125*abd61d1fSMauro Carvalho Chehab @staticmethod 126*abd61d1fSMauro Carvalho Chehab def is_pdf(dtype): 127*abd61d1fSMauro Carvalho Chehab """Ancillary routine to report if a dependency is for PDF generation""" 128*abd61d1fSMauro Carvalho Chehab if dtype[0] == DepManager._PDF_TYPE: 129*abd61d1fSMauro Carvalho Chehab return True 130*abd61d1fSMauro Carvalho Chehab 131*abd61d1fSMauro Carvalho Chehab return False 132*abd61d1fSMauro Carvalho Chehab 133*abd61d1fSMauro Carvalho Chehab def add_package(self, package, dtype): 134*abd61d1fSMauro Carvalho Chehab """ 135*abd61d1fSMauro Carvalho Chehab Add a package at the self.missing() dictionary. 136*abd61d1fSMauro Carvalho Chehab Doesn't update missing_pkg. 137*abd61d1fSMauro Carvalho Chehab """ 138*abd61d1fSMauro Carvalho Chehab is_optional = DepManager.is_optional(dtype) 139*abd61d1fSMauro Carvalho Chehab self.missing[package] = dtype 140*abd61d1fSMauro Carvalho Chehab if is_optional: 141*abd61d1fSMauro Carvalho Chehab self.optional += 1 142*abd61d1fSMauro Carvalho Chehab else: 143*abd61d1fSMauro Carvalho Chehab self.need += 1 144*abd61d1fSMauro Carvalho Chehab 145*abd61d1fSMauro Carvalho Chehab def del_package(self, package): 146*abd61d1fSMauro Carvalho Chehab """ 147*abd61d1fSMauro Carvalho Chehab Remove a package at the self.missing() dictionary. 148*abd61d1fSMauro Carvalho Chehab Doesn't update missing_pkg. 149*abd61d1fSMauro Carvalho Chehab """ 150*abd61d1fSMauro Carvalho Chehab if package in self.missing: 151*abd61d1fSMauro Carvalho Chehab del self.missing[package] 152*abd61d1fSMauro Carvalho Chehab 153*abd61d1fSMauro Carvalho Chehab def clear_deps(self): 154*abd61d1fSMauro Carvalho Chehab """ 155*abd61d1fSMauro Carvalho Chehab Clear dependencies without changing needed/optional. 156*abd61d1fSMauro Carvalho Chehab 157*abd61d1fSMauro Carvalho Chehab This is an ackward way to have a separate section to recommend 158*abd61d1fSMauro Carvalho Chehab a package after system main dependencies. 159*abd61d1fSMauro Carvalho Chehab 160*abd61d1fSMauro Carvalho Chehab TODO: rework the logic to prevent needing it. 161*abd61d1fSMauro Carvalho Chehab """ 162*abd61d1fSMauro Carvalho Chehab 163*abd61d1fSMauro Carvalho Chehab self.missing = {} 164*abd61d1fSMauro Carvalho Chehab self.missing_pkg = {} 165*abd61d1fSMauro Carvalho Chehab 166*abd61d1fSMauro Carvalho Chehab def check_missing(self, progs): 167*abd61d1fSMauro Carvalho Chehab """ 168*abd61d1fSMauro Carvalho Chehab Update self.missing_pkg, using progs dict to convert from the 169*abd61d1fSMauro Carvalho Chehab agnostic package name to distro-specific one. 170*abd61d1fSMauro Carvalho Chehab 171*abd61d1fSMauro Carvalho Chehab Returns an string with the packages to be installed, sorted and 172*abd61d1fSMauro Carvalho Chehab with eventual duplicates removed. 173*abd61d1fSMauro Carvalho Chehab """ 174*abd61d1fSMauro Carvalho Chehab 175*abd61d1fSMauro Carvalho Chehab self.missing_pkg = {} 176*abd61d1fSMauro Carvalho Chehab 177*abd61d1fSMauro Carvalho Chehab for prog, dtype in sorted(self.missing.items()): 178*abd61d1fSMauro Carvalho Chehab # At least on some LTS distros like CentOS 7, texlive doesn't 179*abd61d1fSMauro Carvalho Chehab # provide all packages we need. When such distros are 180*abd61d1fSMauro Carvalho Chehab # detected, we have to disable PDF output. 181*abd61d1fSMauro Carvalho Chehab # 182*abd61d1fSMauro Carvalho Chehab # So, we need to ignore the packages that distros would 183*abd61d1fSMauro Carvalho Chehab # need for LaTeX to work 184*abd61d1fSMauro Carvalho Chehab if DepManager.is_pdf(dtype) and not self.pdf: 185*abd61d1fSMauro Carvalho Chehab self.optional -= 1 186*abd61d1fSMauro Carvalho Chehab continue 187*abd61d1fSMauro Carvalho Chehab 188*abd61d1fSMauro Carvalho Chehab if not dtype in self.missing_pkg: 189*abd61d1fSMauro Carvalho Chehab self.missing_pkg[dtype] = [] 190*abd61d1fSMauro Carvalho Chehab 191*abd61d1fSMauro Carvalho Chehab self.missing_pkg[dtype].append(progs.get(prog, prog)) 192*abd61d1fSMauro Carvalho Chehab 193*abd61d1fSMauro Carvalho Chehab install = [] 194*abd61d1fSMauro Carvalho Chehab for dtype, pkgs in self.missing_pkg.items(): 195*abd61d1fSMauro Carvalho Chehab install += pkgs 196*abd61d1fSMauro Carvalho Chehab 197*abd61d1fSMauro Carvalho Chehab return " ".join(sorted(set(install))) 198*abd61d1fSMauro Carvalho Chehab 199*abd61d1fSMauro Carvalho Chehab def warn_install(self): 200*abd61d1fSMauro Carvalho Chehab """ 201*abd61d1fSMauro Carvalho Chehab Emit warnings/errors related to missing packages. 202*abd61d1fSMauro Carvalho Chehab """ 203*abd61d1fSMauro Carvalho Chehab 204*abd61d1fSMauro Carvalho Chehab output_msg = "" 205*abd61d1fSMauro Carvalho Chehab 206*abd61d1fSMauro Carvalho Chehab for dtype in sorted(self.missing_pkg.keys()): 207*abd61d1fSMauro Carvalho Chehab progs = " ".join(sorted(set(self.missing_pkg[dtype]))) 208*abd61d1fSMauro Carvalho Chehab 209*abd61d1fSMauro Carvalho Chehab try: 210*abd61d1fSMauro Carvalho Chehab name = DepManager.name(dtype) 211*abd61d1fSMauro Carvalho Chehab output_msg += f'{name}:\t{progs}\n' 212*abd61d1fSMauro Carvalho Chehab except KeyError: 213*abd61d1fSMauro Carvalho Chehab raise KeyError(f"ERROR!!!: invalid dtype for {progs}: {dtype}") 214*abd61d1fSMauro Carvalho Chehab 215*abd61d1fSMauro Carvalho Chehab if output_msg: 216*abd61d1fSMauro Carvalho Chehab print(f"\n{output_msg}") 217*abd61d1fSMauro Carvalho Chehab 218*abd61d1fSMauro Carvalho Chehabclass AncillaryMethods: 219*abd61d1fSMauro Carvalho Chehab """ 220*abd61d1fSMauro Carvalho Chehab Ancillary methods that checks for missing dependencies for different 221*abd61d1fSMauro Carvalho Chehab types of types, like binaries, python modules, rpm deps, etc. 222*abd61d1fSMauro Carvalho Chehab """ 223*abd61d1fSMauro Carvalho Chehab 224*abd61d1fSMauro Carvalho Chehab @staticmethod 225*abd61d1fSMauro Carvalho Chehab def which(prog): 226*abd61d1fSMauro Carvalho Chehab """ 227*abd61d1fSMauro Carvalho Chehab Our own implementation of which(). We could instead use 228*abd61d1fSMauro Carvalho Chehab shutil.which(), but this function is simple enough. 229*abd61d1fSMauro Carvalho Chehab Probably faster to use this implementation than to import shutil. 230*abd61d1fSMauro Carvalho Chehab """ 231*abd61d1fSMauro Carvalho Chehab for path in os.environ.get("PATH", "").split(":"): 232*abd61d1fSMauro Carvalho Chehab full_path = os.path.join(path, prog) 233*abd61d1fSMauro Carvalho Chehab if os.access(full_path, os.X_OK): 234*abd61d1fSMauro Carvalho Chehab return full_path 235*abd61d1fSMauro Carvalho Chehab 236*abd61d1fSMauro Carvalho Chehab return None 237*abd61d1fSMauro Carvalho Chehab 238*abd61d1fSMauro Carvalho Chehab @staticmethod 239*abd61d1fSMauro Carvalho Chehab def get_python_version(cmd): 240*abd61d1fSMauro Carvalho Chehab """ 241*abd61d1fSMauro Carvalho Chehab Get python version from a Python binary. As we need to detect if 242*abd61d1fSMauro Carvalho Chehab are out there newer python binaries, we can't rely on sys.release here. 243*abd61d1fSMauro Carvalho Chehab """ 244*abd61d1fSMauro Carvalho Chehab 245*abd61d1fSMauro Carvalho Chehab result = SphinxDependencyChecker.run([cmd, "--version"], 246*abd61d1fSMauro Carvalho Chehab capture_output=True, text=True) 247*abd61d1fSMauro Carvalho Chehab version = result.stdout.strip() 248*abd61d1fSMauro Carvalho Chehab 249*abd61d1fSMauro Carvalho Chehab match = re.search(r"(\d+\.\d+\.\d+)", version) 250*abd61d1fSMauro Carvalho Chehab if match: 251*abd61d1fSMauro Carvalho Chehab return parse_version(match.group(1)) 252*abd61d1fSMauro Carvalho Chehab 253*abd61d1fSMauro Carvalho Chehab print(f"Can't parse version {version}") 254*abd61d1fSMauro Carvalho Chehab return (0, 0, 0) 255*abd61d1fSMauro Carvalho Chehab 256*abd61d1fSMauro Carvalho Chehab @staticmethod 257*abd61d1fSMauro Carvalho Chehab def find_python(): 258*abd61d1fSMauro Carvalho Chehab """ 259*abd61d1fSMauro Carvalho Chehab Detect if are out there any python 3.xy version newer than the 260*abd61d1fSMauro Carvalho Chehab current one. 261*abd61d1fSMauro Carvalho Chehab 262*abd61d1fSMauro Carvalho Chehab Note: this routine is limited to up to 2 digits for python3. We 263*abd61d1fSMauro Carvalho Chehab may need to update it one day, hopefully on a distant future. 264*abd61d1fSMauro Carvalho Chehab """ 265*abd61d1fSMauro Carvalho Chehab patterns = [ 266*abd61d1fSMauro Carvalho Chehab "python3.[0-9]", 267*abd61d1fSMauro Carvalho Chehab "python3.[0-9][0-9]", 268*abd61d1fSMauro Carvalho Chehab ] 269*abd61d1fSMauro Carvalho Chehab 270*abd61d1fSMauro Carvalho Chehab # Seek for a python binary newer than MIN_PYTHON_VERSION 271*abd61d1fSMauro Carvalho Chehab for path in os.getenv("PATH", "").split(":"): 272*abd61d1fSMauro Carvalho Chehab for pattern in patterns: 273*abd61d1fSMauro Carvalho Chehab for cmd in glob(os.path.join(path, pattern)): 274*abd61d1fSMauro Carvalho Chehab if os.path.isfile(cmd) and os.access(cmd, os.X_OK): 275*abd61d1fSMauro Carvalho Chehab version = SphinxDependencyChecker.get_python_version(cmd) 276*abd61d1fSMauro Carvalho Chehab if version >= MIN_PYTHON_VERSION: 277*abd61d1fSMauro Carvalho Chehab return cmd 278*abd61d1fSMauro Carvalho Chehab 279*abd61d1fSMauro Carvalho Chehab @staticmethod 280*abd61d1fSMauro Carvalho Chehab def check_python(): 281*abd61d1fSMauro Carvalho Chehab """ 282*abd61d1fSMauro Carvalho Chehab Check if the current python binary satisfies our minimal requirement 283*abd61d1fSMauro Carvalho Chehab for Sphinx build. If not, re-run with a newer version if found. 284*abd61d1fSMauro Carvalho Chehab """ 285*abd61d1fSMauro Carvalho Chehab cur_ver = sys.version_info[:3] 286*abd61d1fSMauro Carvalho Chehab if cur_ver >= MIN_PYTHON_VERSION: 287*abd61d1fSMauro Carvalho Chehab ver = ver_str(cur_ver) 288*abd61d1fSMauro Carvalho Chehab print(f"Python version: {ver}") 289*abd61d1fSMauro Carvalho Chehab 290*abd61d1fSMauro Carvalho Chehab # This could be useful for debugging purposes 291*abd61d1fSMauro Carvalho Chehab if SphinxDependencyChecker.which("docutils"): 292*abd61d1fSMauro Carvalho Chehab result = SphinxDependencyChecker.run(["docutils", "--version"], 293*abd61d1fSMauro Carvalho Chehab capture_output=True, text=True) 294*abd61d1fSMauro Carvalho Chehab ver = result.stdout.strip() 295*abd61d1fSMauro Carvalho Chehab match = re.search(r"(\d+\.\d+\.\d+)", ver) 296*abd61d1fSMauro Carvalho Chehab if match: 297*abd61d1fSMauro Carvalho Chehab ver = match.group(1) 298*abd61d1fSMauro Carvalho Chehab 299*abd61d1fSMauro Carvalho Chehab print(f"Docutils version: {ver}") 300*abd61d1fSMauro Carvalho Chehab 301*abd61d1fSMauro Carvalho Chehab return 302*abd61d1fSMauro Carvalho Chehab 303*abd61d1fSMauro Carvalho Chehab python_ver = ver_str(cur_ver) 304*abd61d1fSMauro Carvalho Chehab 305*abd61d1fSMauro Carvalho Chehab new_python_cmd = SphinxDependencyChecker.find_python() 306*abd61d1fSMauro Carvalho Chehab if not new_python_cmd: 307*abd61d1fSMauro Carvalho Chehab print(f"ERROR: Python version {python_ver} is not spported anymore\n") 308*abd61d1fSMauro Carvalho Chehab print(" Can't find a new version. This script may fail") 309*abd61d1fSMauro Carvalho Chehab return 310*abd61d1fSMauro Carvalho Chehab 311*abd61d1fSMauro Carvalho Chehab # Restart script using the newer version 312*abd61d1fSMauro Carvalho Chehab script_path = os.path.abspath(sys.argv[0]) 313*abd61d1fSMauro Carvalho Chehab args = [new_python_cmd, script_path] + sys.argv[1:] 314*abd61d1fSMauro Carvalho Chehab 315*abd61d1fSMauro Carvalho Chehab print(f"Python {python_ver} not supported. Changing to {new_python_cmd}") 316*abd61d1fSMauro Carvalho Chehab 317*abd61d1fSMauro Carvalho Chehab try: 318*abd61d1fSMauro Carvalho Chehab os.execv(new_python_cmd, args) 319*abd61d1fSMauro Carvalho Chehab except OSError as e: 320*abd61d1fSMauro Carvalho Chehab sys.exit(f"Failed to restart with {new_python_cmd}: {e}") 321*abd61d1fSMauro Carvalho Chehab 322*abd61d1fSMauro Carvalho Chehab @staticmethod 323*abd61d1fSMauro Carvalho Chehab def run(*args, **kwargs): 324*abd61d1fSMauro Carvalho Chehab """ 325*abd61d1fSMauro Carvalho Chehab Excecute a command, hiding its output by default. 326*abd61d1fSMauro Carvalho Chehab Preserve comatibility with older Python versions. 327*abd61d1fSMauro Carvalho Chehab """ 328*abd61d1fSMauro Carvalho Chehab 329*abd61d1fSMauro Carvalho Chehab capture_output = kwargs.pop('capture_output', False) 330*abd61d1fSMauro Carvalho Chehab 331*abd61d1fSMauro Carvalho Chehab if capture_output: 332*abd61d1fSMauro Carvalho Chehab if 'stdout' not in kwargs: 333*abd61d1fSMauro Carvalho Chehab kwargs['stdout'] = subprocess.PIPE 334*abd61d1fSMauro Carvalho Chehab if 'stderr' not in kwargs: 335*abd61d1fSMauro Carvalho Chehab kwargs['stderr'] = subprocess.PIPE 336*abd61d1fSMauro Carvalho Chehab else: 337*abd61d1fSMauro Carvalho Chehab if 'stdout' not in kwargs: 338*abd61d1fSMauro Carvalho Chehab kwargs['stdout'] = subprocess.DEVNULL 339*abd61d1fSMauro Carvalho Chehab if 'stderr' not in kwargs: 340*abd61d1fSMauro Carvalho Chehab kwargs['stderr'] = subprocess.DEVNULL 341*abd61d1fSMauro Carvalho Chehab 342*abd61d1fSMauro Carvalho Chehab # Don't break with older Python versions 343*abd61d1fSMauro Carvalho Chehab if 'text' in kwargs and sys.version_info < (3, 7): 344*abd61d1fSMauro Carvalho Chehab kwargs['universal_newlines'] = kwargs.pop('text') 345*abd61d1fSMauro Carvalho Chehab 346*abd61d1fSMauro Carvalho Chehab return subprocess.run(*args, **kwargs) 347*abd61d1fSMauro Carvalho Chehab 348*abd61d1fSMauro Carvalho Chehabclass MissingCheckers(AncillaryMethods): 349*abd61d1fSMauro Carvalho Chehab """ 350*abd61d1fSMauro Carvalho Chehab Contains some ancillary checkers for different types of binaries and 351*abd61d1fSMauro Carvalho Chehab package managers. 352*abd61d1fSMauro Carvalho Chehab """ 353*abd61d1fSMauro Carvalho Chehab 354*abd61d1fSMauro Carvalho Chehab def __init__(self, args, texlive): 355*abd61d1fSMauro Carvalho Chehab """ 356*abd61d1fSMauro Carvalho Chehab Initialize its internal variables 357*abd61d1fSMauro Carvalho Chehab """ 358*abd61d1fSMauro Carvalho Chehab self.pdf = args.pdf 359*abd61d1fSMauro Carvalho Chehab self.virtualenv = args.virtualenv 360*abd61d1fSMauro Carvalho Chehab self.version_check = args.version_check 361*abd61d1fSMauro Carvalho Chehab self.texlive = texlive 362*abd61d1fSMauro Carvalho Chehab 363*abd61d1fSMauro Carvalho Chehab self.min_version = (0, 0, 0) 364*abd61d1fSMauro Carvalho Chehab self.cur_version = (0, 0, 0) 365*abd61d1fSMauro Carvalho Chehab 366*abd61d1fSMauro Carvalho Chehab self.deps = DepManager(self.pdf) 367*abd61d1fSMauro Carvalho Chehab 368*abd61d1fSMauro Carvalho Chehab self.need_symlink = 0 369*abd61d1fSMauro Carvalho Chehab self.need_sphinx = 0 370*abd61d1fSMauro Carvalho Chehab 371*abd61d1fSMauro Carvalho Chehab self.verbose_warn_install = 1 372*abd61d1fSMauro Carvalho Chehab 373*abd61d1fSMauro Carvalho Chehab self.virtenv_dir = "" 374*abd61d1fSMauro Carvalho Chehab self.install = "" 375*abd61d1fSMauro Carvalho Chehab self.python_cmd = "" 376*abd61d1fSMauro Carvalho Chehab 377*abd61d1fSMauro Carvalho Chehab self.virtenv_prefix = ["sphinx_", "Sphinx_" ] 378*abd61d1fSMauro Carvalho Chehab 379*abd61d1fSMauro Carvalho Chehab def check_missing_file(self, files, package, dtype): 380*abd61d1fSMauro Carvalho Chehab """ 381*abd61d1fSMauro Carvalho Chehab Does the file exists? If not, add it to missing dependencies. 382*abd61d1fSMauro Carvalho Chehab """ 383*abd61d1fSMauro Carvalho Chehab for f in files: 384*abd61d1fSMauro Carvalho Chehab if os.path.exists(f): 385*abd61d1fSMauro Carvalho Chehab return 386*abd61d1fSMauro Carvalho Chehab self.deps.add_package(package, dtype) 387*abd61d1fSMauro Carvalho Chehab 388*abd61d1fSMauro Carvalho Chehab def check_program(self, prog, dtype): 389*abd61d1fSMauro Carvalho Chehab """ 390*abd61d1fSMauro Carvalho Chehab Does the program exists and it is at the PATH? 391*abd61d1fSMauro Carvalho Chehab If not, add it to missing dependencies. 392*abd61d1fSMauro Carvalho Chehab """ 393*abd61d1fSMauro Carvalho Chehab found = self.which(prog) 394*abd61d1fSMauro Carvalho Chehab if found: 395*abd61d1fSMauro Carvalho Chehab return found 396*abd61d1fSMauro Carvalho Chehab 397*abd61d1fSMauro Carvalho Chehab self.deps.add_package(prog, dtype) 398*abd61d1fSMauro Carvalho Chehab 399*abd61d1fSMauro Carvalho Chehab return None 400*abd61d1fSMauro Carvalho Chehab 401*abd61d1fSMauro Carvalho Chehab def check_perl_module(self, prog, dtype): 402*abd61d1fSMauro Carvalho Chehab """ 403*abd61d1fSMauro Carvalho Chehab Does perl have a dependency? Is it available? 404*abd61d1fSMauro Carvalho Chehab If not, add it to missing dependencies. 405*abd61d1fSMauro Carvalho Chehab 406*abd61d1fSMauro Carvalho Chehab Right now, we still need Perl for doc build, as it is required 407*abd61d1fSMauro Carvalho Chehab by some tools called at docs or kernel build time, like: 408*abd61d1fSMauro Carvalho Chehab 409*abd61d1fSMauro Carvalho Chehab scripts/documentation-file-ref-check 410*abd61d1fSMauro Carvalho Chehab 411*abd61d1fSMauro Carvalho Chehab Also, checkpatch is on Perl. 412*abd61d1fSMauro Carvalho Chehab """ 413*abd61d1fSMauro Carvalho Chehab 414*abd61d1fSMauro Carvalho Chehab # While testing with lxc download template, one of the 415*abd61d1fSMauro Carvalho Chehab # distros (Oracle) didn't have perl - nor even an option to install 416*abd61d1fSMauro Carvalho Chehab # before installing oraclelinux-release-el9 package. 417*abd61d1fSMauro Carvalho Chehab # 418*abd61d1fSMauro Carvalho Chehab # Check it before running an error. If perl is not there, 419*abd61d1fSMauro Carvalho Chehab # add it as a mandatory package, as some parts of the doc builder 420*abd61d1fSMauro Carvalho Chehab # needs it. 421*abd61d1fSMauro Carvalho Chehab if not self.which("perl"): 422*abd61d1fSMauro Carvalho Chehab self.deps.add_package("perl", DepManager.SYSTEM_MANDATORY) 423*abd61d1fSMauro Carvalho Chehab self.deps.add_package(prog, dtype) 424*abd61d1fSMauro Carvalho Chehab return 425*abd61d1fSMauro Carvalho Chehab 426*abd61d1fSMauro Carvalho Chehab try: 427*abd61d1fSMauro Carvalho Chehab self.run(["perl", f"-M{prog}", "-e", "1"], check=True) 428*abd61d1fSMauro Carvalho Chehab except subprocess.CalledProcessError: 429*abd61d1fSMauro Carvalho Chehab self.deps.add_package(prog, dtype) 430*abd61d1fSMauro Carvalho Chehab 431*abd61d1fSMauro Carvalho Chehab def check_python_module(self, module, is_optional=False): 432*abd61d1fSMauro Carvalho Chehab """ 433*abd61d1fSMauro Carvalho Chehab Does a python module exists outside venv? If not, add it to missing 434*abd61d1fSMauro Carvalho Chehab dependencies. 435*abd61d1fSMauro Carvalho Chehab """ 436*abd61d1fSMauro Carvalho Chehab if is_optional: 437*abd61d1fSMauro Carvalho Chehab dtype = DepManager.PYTHON_OPTIONAL 438*abd61d1fSMauro Carvalho Chehab else: 439*abd61d1fSMauro Carvalho Chehab dtype = DepManager.PYTHON_MANDATORY 440*abd61d1fSMauro Carvalho Chehab 441*abd61d1fSMauro Carvalho Chehab try: 442*abd61d1fSMauro Carvalho Chehab self.run([self.python_cmd, "-c", f"import {module}"], check=True) 443*abd61d1fSMauro Carvalho Chehab except subprocess.CalledProcessError: 444*abd61d1fSMauro Carvalho Chehab self.deps.add_package(module, dtype) 445*abd61d1fSMauro Carvalho Chehab 446*abd61d1fSMauro Carvalho Chehab def check_rpm_missing(self, pkgs, dtype): 447*abd61d1fSMauro Carvalho Chehab """ 448*abd61d1fSMauro Carvalho Chehab Does a rpm package exists? If not, add it to missing dependencies. 449*abd61d1fSMauro Carvalho Chehab """ 450*abd61d1fSMauro Carvalho Chehab for prog in pkgs: 451*abd61d1fSMauro Carvalho Chehab try: 452*abd61d1fSMauro Carvalho Chehab self.run(["rpm", "-q", prog], check=True) 453*abd61d1fSMauro Carvalho Chehab except subprocess.CalledProcessError: 454*abd61d1fSMauro Carvalho Chehab self.deps.add_package(prog, dtype) 455*abd61d1fSMauro Carvalho Chehab 456*abd61d1fSMauro Carvalho Chehab def check_pacman_missing(self, pkgs, dtype): 457*abd61d1fSMauro Carvalho Chehab """ 458*abd61d1fSMauro Carvalho Chehab Does a pacman package exists? If not, add it to missing dependencies. 459*abd61d1fSMauro Carvalho Chehab """ 460*abd61d1fSMauro Carvalho Chehab for prog in pkgs: 461*abd61d1fSMauro Carvalho Chehab try: 462*abd61d1fSMauro Carvalho Chehab self.run(["pacman", "-Q", prog], check=True) 463*abd61d1fSMauro Carvalho Chehab except subprocess.CalledProcessError: 464*abd61d1fSMauro Carvalho Chehab self.deps.add_package(prog, dtype) 465*abd61d1fSMauro Carvalho Chehab 466*abd61d1fSMauro Carvalho Chehab def check_missing_tex(self, is_optional=False): 467*abd61d1fSMauro Carvalho Chehab """ 468*abd61d1fSMauro Carvalho Chehab Does a LaTeX package exists? If not, add it to missing dependencies. 469*abd61d1fSMauro Carvalho Chehab """ 470*abd61d1fSMauro Carvalho Chehab if is_optional: 471*abd61d1fSMauro Carvalho Chehab dtype = DepManager.PDF_OPTIONAL 472*abd61d1fSMauro Carvalho Chehab else: 473*abd61d1fSMauro Carvalho Chehab dtype = DepManager.PDF_MANDATORY 474*abd61d1fSMauro Carvalho Chehab 475*abd61d1fSMauro Carvalho Chehab kpsewhich = self.which("kpsewhich") 476*abd61d1fSMauro Carvalho Chehab for prog, package in self.texlive.items(): 477*abd61d1fSMauro Carvalho Chehab 478*abd61d1fSMauro Carvalho Chehab # If kpsewhich is not there, just add it to deps 479*abd61d1fSMauro Carvalho Chehab if not kpsewhich: 480*abd61d1fSMauro Carvalho Chehab self.deps.add_package(package, dtype) 481*abd61d1fSMauro Carvalho Chehab continue 482*abd61d1fSMauro Carvalho Chehab 483*abd61d1fSMauro Carvalho Chehab # Check if the package is needed 484*abd61d1fSMauro Carvalho Chehab try: 485*abd61d1fSMauro Carvalho Chehab result = self.run( 486*abd61d1fSMauro Carvalho Chehab [kpsewhich, prog], stdout=subprocess.PIPE, text=True, check=True 487*abd61d1fSMauro Carvalho Chehab ) 488*abd61d1fSMauro Carvalho Chehab 489*abd61d1fSMauro Carvalho Chehab # Didn't find. Add it 490*abd61d1fSMauro Carvalho Chehab if not result.stdout.strip(): 491*abd61d1fSMauro Carvalho Chehab self.deps.add_package(package, dtype) 492*abd61d1fSMauro Carvalho Chehab 493*abd61d1fSMauro Carvalho Chehab except subprocess.CalledProcessError: 494*abd61d1fSMauro Carvalho Chehab # kpsewhich returned an error. Add it, just in case 495*abd61d1fSMauro Carvalho Chehab self.deps.add_package(package, dtype) 496*abd61d1fSMauro Carvalho Chehab 497*abd61d1fSMauro Carvalho Chehab def get_sphinx_fname(self): 498*abd61d1fSMauro Carvalho Chehab """ 499*abd61d1fSMauro Carvalho Chehab Gets the binary filename for sphinx-build. 500*abd61d1fSMauro Carvalho Chehab """ 501*abd61d1fSMauro Carvalho Chehab if "SPHINXBUILD" in os.environ: 502*abd61d1fSMauro Carvalho Chehab return os.environ["SPHINXBUILD"] 503*abd61d1fSMauro Carvalho Chehab 504*abd61d1fSMauro Carvalho Chehab fname = "sphinx-build" 505*abd61d1fSMauro Carvalho Chehab if self.which(fname): 506*abd61d1fSMauro Carvalho Chehab return fname 507*abd61d1fSMauro Carvalho Chehab 508*abd61d1fSMauro Carvalho Chehab fname = "sphinx-build-3" 509*abd61d1fSMauro Carvalho Chehab if self.which(fname): 510*abd61d1fSMauro Carvalho Chehab self.need_symlink = 1 511*abd61d1fSMauro Carvalho Chehab return fname 512*abd61d1fSMauro Carvalho Chehab 513*abd61d1fSMauro Carvalho Chehab return "" 514*abd61d1fSMauro Carvalho Chehab 515*abd61d1fSMauro Carvalho Chehab def get_sphinx_version(self, cmd): 516*abd61d1fSMauro Carvalho Chehab """ 517*abd61d1fSMauro Carvalho Chehab Gets sphinx-build version. 518*abd61d1fSMauro Carvalho Chehab """ 519*abd61d1fSMauro Carvalho Chehab try: 520*abd61d1fSMauro Carvalho Chehab result = self.run([cmd, "--version"], 521*abd61d1fSMauro Carvalho Chehab stdout=subprocess.PIPE, 522*abd61d1fSMauro Carvalho Chehab stderr=subprocess.STDOUT, 523*abd61d1fSMauro Carvalho Chehab text=True, check=True) 524*abd61d1fSMauro Carvalho Chehab except (subprocess.CalledProcessError, FileNotFoundError): 525*abd61d1fSMauro Carvalho Chehab return None 526*abd61d1fSMauro Carvalho Chehab 527*abd61d1fSMauro Carvalho Chehab for line in result.stdout.split("\n"): 528*abd61d1fSMauro Carvalho Chehab match = re.match(r"^sphinx-build\s+([\d\.]+)(?:\+(?:/[\da-f]+)|b\d+)?\s*$", line) 529*abd61d1fSMauro Carvalho Chehab if match: 530*abd61d1fSMauro Carvalho Chehab return parse_version(match.group(1)) 531*abd61d1fSMauro Carvalho Chehab 532*abd61d1fSMauro Carvalho Chehab match = re.match(r"^Sphinx.*\s+([\d\.]+)\s*$", line) 533*abd61d1fSMauro Carvalho Chehab if match: 534*abd61d1fSMauro Carvalho Chehab return parse_version(match.group(1)) 535*abd61d1fSMauro Carvalho Chehab 536*abd61d1fSMauro Carvalho Chehab def check_sphinx(self, conf): 537*abd61d1fSMauro Carvalho Chehab """ 538*abd61d1fSMauro Carvalho Chehab Checks Sphinx minimal requirements 539*abd61d1fSMauro Carvalho Chehab """ 540*abd61d1fSMauro Carvalho Chehab try: 541*abd61d1fSMauro Carvalho Chehab with open(conf, "r", encoding="utf-8") as f: 542*abd61d1fSMauro Carvalho Chehab for line in f: 543*abd61d1fSMauro Carvalho Chehab match = re.match(r"^\s*needs_sphinx\s*=\s*[\'\"]([\d\.]+)[\'\"]", line) 544*abd61d1fSMauro Carvalho Chehab if match: 545*abd61d1fSMauro Carvalho Chehab self.min_version = parse_version(match.group(1)) 546*abd61d1fSMauro Carvalho Chehab break 547*abd61d1fSMauro Carvalho Chehab except IOError: 548*abd61d1fSMauro Carvalho Chehab sys.exit(f"Can't open {conf}") 549*abd61d1fSMauro Carvalho Chehab 550*abd61d1fSMauro Carvalho Chehab if not self.min_version: 551*abd61d1fSMauro Carvalho Chehab sys.exit(f"Can't get needs_sphinx version from {conf}") 552*abd61d1fSMauro Carvalho Chehab 553*abd61d1fSMauro Carvalho Chehab self.virtenv_dir = self.virtenv_prefix[0] + "latest" 554*abd61d1fSMauro Carvalho Chehab 555*abd61d1fSMauro Carvalho Chehab sphinx = self.get_sphinx_fname() 556*abd61d1fSMauro Carvalho Chehab if not sphinx: 557*abd61d1fSMauro Carvalho Chehab self.need_sphinx = 1 558*abd61d1fSMauro Carvalho Chehab return 559*abd61d1fSMauro Carvalho Chehab 560*abd61d1fSMauro Carvalho Chehab self.cur_version = self.get_sphinx_version(sphinx) 561*abd61d1fSMauro Carvalho Chehab if not self.cur_version: 562*abd61d1fSMauro Carvalho Chehab sys.exit(f"{sphinx} didn't return its version") 563*abd61d1fSMauro Carvalho Chehab 564*abd61d1fSMauro Carvalho Chehab if self.cur_version < self.min_version: 565*abd61d1fSMauro Carvalho Chehab curver = ver_str(self.cur_version) 566*abd61d1fSMauro Carvalho Chehab minver = ver_str(self.min_version) 567*abd61d1fSMauro Carvalho Chehab 568*abd61d1fSMauro Carvalho Chehab print(f"ERROR: Sphinx version is {curver}. It should be >= {minver}") 569*abd61d1fSMauro Carvalho Chehab self.need_sphinx = 1 570*abd61d1fSMauro Carvalho Chehab return 571*abd61d1fSMauro Carvalho Chehab 572*abd61d1fSMauro Carvalho Chehab # On version check mode, just assume Sphinx has all mandatory deps 573*abd61d1fSMauro Carvalho Chehab if self.version_check and self.cur_version >= RECOMMENDED_VERSION: 574*abd61d1fSMauro Carvalho Chehab sys.exit(0) 575*abd61d1fSMauro Carvalho Chehab 576*abd61d1fSMauro Carvalho Chehab def catcheck(self, filename): 577*abd61d1fSMauro Carvalho Chehab """ 578*abd61d1fSMauro Carvalho Chehab Reads a file if it exists, returning as string. 579*abd61d1fSMauro Carvalho Chehab If not found, returns an empty string. 580*abd61d1fSMauro Carvalho Chehab """ 581*abd61d1fSMauro Carvalho Chehab if os.path.exists(filename): 582*abd61d1fSMauro Carvalho Chehab with open(filename, "r", encoding="utf-8") as f: 583*abd61d1fSMauro Carvalho Chehab return f.read().strip() 584*abd61d1fSMauro Carvalho Chehab return "" 585*abd61d1fSMauro Carvalho Chehab 586*abd61d1fSMauro Carvalho Chehab def get_system_release(self): 587*abd61d1fSMauro Carvalho Chehab """ 588*abd61d1fSMauro Carvalho Chehab Determine the system type. There's no unique way that would work 589*abd61d1fSMauro Carvalho Chehab with all distros with a minimal package install. So, several 590*abd61d1fSMauro Carvalho Chehab methods are used here. 591*abd61d1fSMauro Carvalho Chehab 592*abd61d1fSMauro Carvalho Chehab By default, it will use lsb_release function. If not available, it will 593*abd61d1fSMauro Carvalho Chehab fail back to reading the known different places where the distro name 594*abd61d1fSMauro Carvalho Chehab is stored. 595*abd61d1fSMauro Carvalho Chehab 596*abd61d1fSMauro Carvalho Chehab Several modern distros now have /etc/os-release, which usually have 597*abd61d1fSMauro Carvalho Chehab a decent coverage. 598*abd61d1fSMauro Carvalho Chehab """ 599*abd61d1fSMauro Carvalho Chehab 600*abd61d1fSMauro Carvalho Chehab system_release = "" 601*abd61d1fSMauro Carvalho Chehab 602*abd61d1fSMauro Carvalho Chehab if self.which("lsb_release"): 603*abd61d1fSMauro Carvalho Chehab result = self.run(["lsb_release", "-d"], capture_output=True, text=True) 604*abd61d1fSMauro Carvalho Chehab system_release = result.stdout.replace("Description:", "").strip() 605*abd61d1fSMauro Carvalho Chehab 606*abd61d1fSMauro Carvalho Chehab release_files = [ 607*abd61d1fSMauro Carvalho Chehab "/etc/system-release", 608*abd61d1fSMauro Carvalho Chehab "/etc/redhat-release", 609*abd61d1fSMauro Carvalho Chehab "/etc/lsb-release", 610*abd61d1fSMauro Carvalho Chehab "/etc/gentoo-release", 611*abd61d1fSMauro Carvalho Chehab ] 612*abd61d1fSMauro Carvalho Chehab 613*abd61d1fSMauro Carvalho Chehab if not system_release: 614*abd61d1fSMauro Carvalho Chehab for f in release_files: 615*abd61d1fSMauro Carvalho Chehab system_release = self.catcheck(f) 616*abd61d1fSMauro Carvalho Chehab if system_release: 617*abd61d1fSMauro Carvalho Chehab break 618*abd61d1fSMauro Carvalho Chehab 619*abd61d1fSMauro Carvalho Chehab # This seems more common than LSB these days 620*abd61d1fSMauro Carvalho Chehab if not system_release: 621*abd61d1fSMauro Carvalho Chehab os_var = {} 622*abd61d1fSMauro Carvalho Chehab try: 623*abd61d1fSMauro Carvalho Chehab with open("/etc/os-release", "r", encoding="utf-8") as f: 624*abd61d1fSMauro Carvalho Chehab for line in f: 625*abd61d1fSMauro Carvalho Chehab match = re.match(r"^([\w\d\_]+)=\"?([^\"]*)\"?\n", line) 626*abd61d1fSMauro Carvalho Chehab if match: 627*abd61d1fSMauro Carvalho Chehab os_var[match.group(1)] = match.group(2) 628*abd61d1fSMauro Carvalho Chehab 629*abd61d1fSMauro Carvalho Chehab system_release = os_var.get("NAME", "") 630*abd61d1fSMauro Carvalho Chehab if "VERSION_ID" in os_var: 631*abd61d1fSMauro Carvalho Chehab system_release += " " + os_var["VERSION_ID"] 632*abd61d1fSMauro Carvalho Chehab elif "VERSION" in os_var: 633*abd61d1fSMauro Carvalho Chehab system_release += " " + os_var["VERSION"] 634*abd61d1fSMauro Carvalho Chehab except IOError: 635*abd61d1fSMauro Carvalho Chehab pass 636*abd61d1fSMauro Carvalho Chehab 637*abd61d1fSMauro Carvalho Chehab if not system_release: 638*abd61d1fSMauro Carvalho Chehab system_release = self.catcheck("/etc/issue") 639*abd61d1fSMauro Carvalho Chehab 640*abd61d1fSMauro Carvalho Chehab system_release = system_release.strip() 641*abd61d1fSMauro Carvalho Chehab 642*abd61d1fSMauro Carvalho Chehab return system_release 643*abd61d1fSMauro Carvalho Chehab 644*abd61d1fSMauro Carvalho Chehabclass SphinxDependencyChecker(MissingCheckers): 645*abd61d1fSMauro Carvalho Chehab """ 646*abd61d1fSMauro Carvalho Chehab Main class for checking Sphinx documentation build dependencies. 647*abd61d1fSMauro Carvalho Chehab 648*abd61d1fSMauro Carvalho Chehab - Check for missing system packages; 649*abd61d1fSMauro Carvalho Chehab - Check for missing Python modules; 650*abd61d1fSMauro Carvalho Chehab - Check for missing LaTeX packages needed by PDF generation; 651*abd61d1fSMauro Carvalho Chehab - Propose Sphinx install via Python Virtual environment; 652*abd61d1fSMauro Carvalho Chehab - Propose Sphinx install via distro-specific package install. 653*abd61d1fSMauro Carvalho Chehab """ 654*abd61d1fSMauro Carvalho Chehab def __init__(self, args): 655*abd61d1fSMauro Carvalho Chehab """Initialize checker variables""" 656*abd61d1fSMauro Carvalho Chehab 657*abd61d1fSMauro Carvalho Chehab # List of required texlive packages on Fedora and OpenSuse 658*abd61d1fSMauro Carvalho Chehab texlive = { 659*abd61d1fSMauro Carvalho Chehab "amsfonts.sty": "texlive-amsfonts", 660*abd61d1fSMauro Carvalho Chehab "amsmath.sty": "texlive-amsmath", 661*abd61d1fSMauro Carvalho Chehab "amssymb.sty": "texlive-amsfonts", 662*abd61d1fSMauro Carvalho Chehab "amsthm.sty": "texlive-amscls", 663*abd61d1fSMauro Carvalho Chehab "anyfontsize.sty": "texlive-anyfontsize", 664*abd61d1fSMauro Carvalho Chehab "atbegshi.sty": "texlive-oberdiek", 665*abd61d1fSMauro Carvalho Chehab "bm.sty": "texlive-tools", 666*abd61d1fSMauro Carvalho Chehab "capt-of.sty": "texlive-capt-of", 667*abd61d1fSMauro Carvalho Chehab "cmap.sty": "texlive-cmap", 668*abd61d1fSMauro Carvalho Chehab "ctexhook.sty": "texlive-ctex", 669*abd61d1fSMauro Carvalho Chehab "ecrm1000.tfm": "texlive-ec", 670*abd61d1fSMauro Carvalho Chehab "eqparbox.sty": "texlive-eqparbox", 671*abd61d1fSMauro Carvalho Chehab "eu1enc.def": "texlive-euenc", 672*abd61d1fSMauro Carvalho Chehab "fancybox.sty": "texlive-fancybox", 673*abd61d1fSMauro Carvalho Chehab "fancyvrb.sty": "texlive-fancyvrb", 674*abd61d1fSMauro Carvalho Chehab "float.sty": "texlive-float", 675*abd61d1fSMauro Carvalho Chehab "fncychap.sty": "texlive-fncychap", 676*abd61d1fSMauro Carvalho Chehab "footnote.sty": "texlive-mdwtools", 677*abd61d1fSMauro Carvalho Chehab "framed.sty": "texlive-framed", 678*abd61d1fSMauro Carvalho Chehab "luatex85.sty": "texlive-luatex85", 679*abd61d1fSMauro Carvalho Chehab "multirow.sty": "texlive-multirow", 680*abd61d1fSMauro Carvalho Chehab "needspace.sty": "texlive-needspace", 681*abd61d1fSMauro Carvalho Chehab "palatino.sty": "texlive-psnfss", 682*abd61d1fSMauro Carvalho Chehab "parskip.sty": "texlive-parskip", 683*abd61d1fSMauro Carvalho Chehab "polyglossia.sty": "texlive-polyglossia", 684*abd61d1fSMauro Carvalho Chehab "tabulary.sty": "texlive-tabulary", 685*abd61d1fSMauro Carvalho Chehab "threeparttable.sty": "texlive-threeparttable", 686*abd61d1fSMauro Carvalho Chehab "titlesec.sty": "texlive-titlesec", 687*abd61d1fSMauro Carvalho Chehab "ucs.sty": "texlive-ucs", 688*abd61d1fSMauro Carvalho Chehab "upquote.sty": "texlive-upquote", 689*abd61d1fSMauro Carvalho Chehab "wrapfig.sty": "texlive-wrapfig", 690*abd61d1fSMauro Carvalho Chehab } 691*abd61d1fSMauro Carvalho Chehab 692*abd61d1fSMauro Carvalho Chehab super().__init__(args, texlive) 693*abd61d1fSMauro Carvalho Chehab 694*abd61d1fSMauro Carvalho Chehab self.need_pip = False 695*abd61d1fSMauro Carvalho Chehab self.rec_sphinx_upgrade = 0 696*abd61d1fSMauro Carvalho Chehab 697*abd61d1fSMauro Carvalho Chehab self.system_release = self.get_system_release() 698*abd61d1fSMauro Carvalho Chehab self.activate_cmd = "" 699*abd61d1fSMauro Carvalho Chehab 700*abd61d1fSMauro Carvalho Chehab # Some distros may not have a Sphinx shipped package compatible with 701*abd61d1fSMauro Carvalho Chehab # our minimal requirements 702*abd61d1fSMauro Carvalho Chehab self.package_supported = True 703*abd61d1fSMauro Carvalho Chehab 704*abd61d1fSMauro Carvalho Chehab # Recommend a new python version 705*abd61d1fSMauro Carvalho Chehab self.recommend_python = None 706*abd61d1fSMauro Carvalho Chehab 707*abd61d1fSMauro Carvalho Chehab # Certain hints are meant to be shown only once 708*abd61d1fSMauro Carvalho Chehab self.distro_msg = None 709*abd61d1fSMauro Carvalho Chehab 710*abd61d1fSMauro Carvalho Chehab self.latest_avail_ver = (0, 0, 0) 711*abd61d1fSMauro Carvalho Chehab self.venv_ver = (0, 0, 0) 712*abd61d1fSMauro Carvalho Chehab 713*abd61d1fSMauro Carvalho Chehab prefix = os.environ.get("srctree", ".") + "/" 714*abd61d1fSMauro Carvalho Chehab 715*abd61d1fSMauro Carvalho Chehab self.conf = prefix + "Documentation/conf.py" 716*abd61d1fSMauro Carvalho Chehab self.requirement_file = prefix + "Documentation/sphinx/requirements.txt" 717*abd61d1fSMauro Carvalho Chehab 718*abd61d1fSMauro Carvalho Chehab def get_install_progs(self, progs, cmd, extra=None): 719*abd61d1fSMauro Carvalho Chehab """ 720*abd61d1fSMauro Carvalho Chehab Check for missing dependencies using the provided program mapping. 721*abd61d1fSMauro Carvalho Chehab 722*abd61d1fSMauro Carvalho Chehab The actual distro-specific programs are mapped via progs argument. 723*abd61d1fSMauro Carvalho Chehab """ 724*abd61d1fSMauro Carvalho Chehab install = self.deps.check_missing(progs) 725*abd61d1fSMauro Carvalho Chehab 726*abd61d1fSMauro Carvalho Chehab if self.verbose_warn_install: 727*abd61d1fSMauro Carvalho Chehab self.deps.warn_install() 728*abd61d1fSMauro Carvalho Chehab 729*abd61d1fSMauro Carvalho Chehab if not install: 730*abd61d1fSMauro Carvalho Chehab return 731*abd61d1fSMauro Carvalho Chehab 732*abd61d1fSMauro Carvalho Chehab if cmd: 733*abd61d1fSMauro Carvalho Chehab if self.verbose_warn_install: 734*abd61d1fSMauro Carvalho Chehab msg = "You should run:" 735*abd61d1fSMauro Carvalho Chehab else: 736*abd61d1fSMauro Carvalho Chehab msg = "" 737*abd61d1fSMauro Carvalho Chehab 738*abd61d1fSMauro Carvalho Chehab if extra: 739*abd61d1fSMauro Carvalho Chehab msg += "\n\t" + extra.replace("\n", "\n\t") 740*abd61d1fSMauro Carvalho Chehab 741*abd61d1fSMauro Carvalho Chehab return(msg + "\n\tsudo " + cmd + " " + install) 742*abd61d1fSMauro Carvalho Chehab 743*abd61d1fSMauro Carvalho Chehab return None 744*abd61d1fSMauro Carvalho Chehab 745*abd61d1fSMauro Carvalho Chehab # 746*abd61d1fSMauro Carvalho Chehab # Distro-specific hints methods 747*abd61d1fSMauro Carvalho Chehab # 748*abd61d1fSMauro Carvalho Chehab 749*abd61d1fSMauro Carvalho Chehab def give_debian_hints(self): 750*abd61d1fSMauro Carvalho Chehab """ 751*abd61d1fSMauro Carvalho Chehab Provide package installation hints for Debian-based distros. 752*abd61d1fSMauro Carvalho Chehab """ 753*abd61d1fSMauro Carvalho Chehab progs = { 754*abd61d1fSMauro Carvalho Chehab "Pod::Usage": "perl-modules", 755*abd61d1fSMauro Carvalho Chehab "convert": "imagemagick", 756*abd61d1fSMauro Carvalho Chehab "dot": "graphviz", 757*abd61d1fSMauro Carvalho Chehab "ensurepip": "python3-venv", 758*abd61d1fSMauro Carvalho Chehab "python-sphinx": "python3-sphinx", 759*abd61d1fSMauro Carvalho Chehab "rsvg-convert": "librsvg2-bin", 760*abd61d1fSMauro Carvalho Chehab "virtualenv": "virtualenv", 761*abd61d1fSMauro Carvalho Chehab "xelatex": "texlive-xetex", 762*abd61d1fSMauro Carvalho Chehab "yaml": "python3-yaml", 763*abd61d1fSMauro Carvalho Chehab } 764*abd61d1fSMauro Carvalho Chehab 765*abd61d1fSMauro Carvalho Chehab if self.pdf: 766*abd61d1fSMauro Carvalho Chehab pdf_pkgs = { 767*abd61d1fSMauro Carvalho Chehab "fonts-dejavu": [ 768*abd61d1fSMauro Carvalho Chehab "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 769*abd61d1fSMauro Carvalho Chehab ], 770*abd61d1fSMauro Carvalho Chehab "fonts-noto-cjk": [ 771*abd61d1fSMauro Carvalho Chehab "/usr/share/fonts/noto-cjk/NotoSansCJK-Regular.ttc", 772*abd61d1fSMauro Carvalho Chehab "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc", 773*abd61d1fSMauro Carvalho Chehab "/usr/share/fonts/opentype/noto/NotoSerifCJK-Regular.ttc", 774*abd61d1fSMauro Carvalho Chehab ], 775*abd61d1fSMauro Carvalho Chehab "tex-gyre": [ 776*abd61d1fSMauro Carvalho Chehab "/usr/share/texmf/tex/latex/tex-gyre/tgtermes.sty" 777*abd61d1fSMauro Carvalho Chehab ], 778*abd61d1fSMauro Carvalho Chehab "texlive-fonts-recommended": [ 779*abd61d1fSMauro Carvalho Chehab "/usr/share/texlive/texmf-dist/fonts/tfm/adobe/zapfding/pzdr.tfm", 780*abd61d1fSMauro Carvalho Chehab ], 781*abd61d1fSMauro Carvalho Chehab "texlive-lang-chinese": [ 782*abd61d1fSMauro Carvalho Chehab "/usr/share/texlive/texmf-dist/tex/latex/ctex/ctexhook.sty", 783*abd61d1fSMauro Carvalho Chehab ], 784*abd61d1fSMauro Carvalho Chehab } 785*abd61d1fSMauro Carvalho Chehab 786*abd61d1fSMauro Carvalho Chehab for package, files in pdf_pkgs.items(): 787*abd61d1fSMauro Carvalho Chehab self.check_missing_file(files, package, DepManager.PDF_MANDATORY) 788*abd61d1fSMauro Carvalho Chehab 789*abd61d1fSMauro Carvalho Chehab self.check_program("dvipng", DepManager.PDF_MANDATORY) 790*abd61d1fSMauro Carvalho Chehab 791*abd61d1fSMauro Carvalho Chehab if not self.distro_msg: 792*abd61d1fSMauro Carvalho Chehab self.distro_msg = \ 793*abd61d1fSMauro Carvalho Chehab "Note: ImageMagick is broken on some distros, affecting PDF output. For more details:\n" \ 794*abd61d1fSMauro Carvalho Chehab "\thttps://askubuntu.com/questions/1158894/imagemagick-still-broken-using-with-usr-bin-convert" 795*abd61d1fSMauro Carvalho Chehab 796*abd61d1fSMauro Carvalho Chehab return self.get_install_progs(progs, "apt-get install") 797*abd61d1fSMauro Carvalho Chehab 798*abd61d1fSMauro Carvalho Chehab def give_redhat_hints(self): 799*abd61d1fSMauro Carvalho Chehab """ 800*abd61d1fSMauro Carvalho Chehab Provide package installation hints for RedHat-based distros 801*abd61d1fSMauro Carvalho Chehab (Fedora, RHEL and RHEL-based variants). 802*abd61d1fSMauro Carvalho Chehab """ 803*abd61d1fSMauro Carvalho Chehab progs = { 804*abd61d1fSMauro Carvalho Chehab "Pod::Usage": "perl-Pod-Usage", 805*abd61d1fSMauro Carvalho Chehab "convert": "ImageMagick", 806*abd61d1fSMauro Carvalho Chehab "dot": "graphviz", 807*abd61d1fSMauro Carvalho Chehab "python-sphinx": "python3-sphinx", 808*abd61d1fSMauro Carvalho Chehab "rsvg-convert": "librsvg2-tools", 809*abd61d1fSMauro Carvalho Chehab "virtualenv": "python3-virtualenv", 810*abd61d1fSMauro Carvalho Chehab "xelatex": "texlive-xetex-bin", 811*abd61d1fSMauro Carvalho Chehab "yaml": "python3-pyyaml", 812*abd61d1fSMauro Carvalho Chehab } 813*abd61d1fSMauro Carvalho Chehab 814*abd61d1fSMauro Carvalho Chehab fedora_tex_pkgs = [ 815*abd61d1fSMauro Carvalho Chehab "dejavu-sans-fonts", 816*abd61d1fSMauro Carvalho Chehab "dejavu-sans-mono-fonts", 817*abd61d1fSMauro Carvalho Chehab "dejavu-serif-fonts", 818*abd61d1fSMauro Carvalho Chehab "texlive-collection-fontsrecommended", 819*abd61d1fSMauro Carvalho Chehab "texlive-collection-latex", 820*abd61d1fSMauro Carvalho Chehab "texlive-xecjk", 821*abd61d1fSMauro Carvalho Chehab ] 822*abd61d1fSMauro Carvalho Chehab 823*abd61d1fSMauro Carvalho Chehab fedora = False 824*abd61d1fSMauro Carvalho Chehab rel = None 825*abd61d1fSMauro Carvalho Chehab 826*abd61d1fSMauro Carvalho Chehab match = re.search(r"(release|Linux)\s+(\d+)", self.system_release) 827*abd61d1fSMauro Carvalho Chehab if match: 828*abd61d1fSMauro Carvalho Chehab rel = int(match.group(2)) 829*abd61d1fSMauro Carvalho Chehab 830*abd61d1fSMauro Carvalho Chehab if not rel: 831*abd61d1fSMauro Carvalho Chehab print("Couldn't identify release number") 832*abd61d1fSMauro Carvalho Chehab noto_sans_redhat = None 833*abd61d1fSMauro Carvalho Chehab self.pdf = False 834*abd61d1fSMauro Carvalho Chehab elif re.search("Fedora", self.system_release): 835*abd61d1fSMauro Carvalho Chehab # Fedora 38 and upper use this CJK font 836*abd61d1fSMauro Carvalho Chehab 837*abd61d1fSMauro Carvalho Chehab noto_sans_redhat = "google-noto-sans-cjk-fonts" 838*abd61d1fSMauro Carvalho Chehab fedora = True 839*abd61d1fSMauro Carvalho Chehab else: 840*abd61d1fSMauro Carvalho Chehab # Almalinux, CentOS, RHEL, ... 841*abd61d1fSMauro Carvalho Chehab 842*abd61d1fSMauro Carvalho Chehab # at least up to version 9 (and Fedora < 38), that's the CJK font 843*abd61d1fSMauro Carvalho Chehab noto_sans_redhat = "google-noto-sans-cjk-ttc-fonts" 844*abd61d1fSMauro Carvalho Chehab 845*abd61d1fSMauro Carvalho Chehab progs["virtualenv"] = "python-virtualenv" 846*abd61d1fSMauro Carvalho Chehab 847*abd61d1fSMauro Carvalho Chehab if not rel or rel < 8: 848*abd61d1fSMauro Carvalho Chehab print("ERROR: Distro not supported. Too old?") 849*abd61d1fSMauro Carvalho Chehab return 850*abd61d1fSMauro Carvalho Chehab 851*abd61d1fSMauro Carvalho Chehab # RHEL 8 uses Python 3.6, which is not compatible with 852*abd61d1fSMauro Carvalho Chehab # the build system anymore. Suggest Python 3.11 853*abd61d1fSMauro Carvalho Chehab if rel == 8: 854*abd61d1fSMauro Carvalho Chehab self.check_program("python3.9", DepManager.SYSTEM_MANDATORY) 855*abd61d1fSMauro Carvalho Chehab progs["python3.9"] = "python39" 856*abd61d1fSMauro Carvalho Chehab progs["yaml"] = "python39-pyyaml" 857*abd61d1fSMauro Carvalho Chehab 858*abd61d1fSMauro Carvalho Chehab self.recommend_python = True 859*abd61d1fSMauro Carvalho Chehab 860*abd61d1fSMauro Carvalho Chehab # There's no python39-sphinx package. Only pip is supported 861*abd61d1fSMauro Carvalho Chehab self.package_supported = False 862*abd61d1fSMauro Carvalho Chehab 863*abd61d1fSMauro Carvalho Chehab if not self.distro_msg: 864*abd61d1fSMauro Carvalho Chehab self.distro_msg = \ 865*abd61d1fSMauro Carvalho Chehab "Note: RHEL-based distros typically require extra repositories.\n" \ 866*abd61d1fSMauro Carvalho Chehab "For most, enabling epel and crb are enough:\n" \ 867*abd61d1fSMauro Carvalho Chehab "\tsudo dnf install -y epel-release\n" \ 868*abd61d1fSMauro Carvalho Chehab "\tsudo dnf config-manager --set-enabled crb\n" \ 869*abd61d1fSMauro Carvalho Chehab "Yet, some may have other required repositories. Those commands could be useful:\n" \ 870*abd61d1fSMauro Carvalho Chehab "\tsudo dnf repolist all\n" \ 871*abd61d1fSMauro Carvalho Chehab "\tsudo dnf repoquery --available --info <pkgs>\n" \ 872*abd61d1fSMauro Carvalho Chehab "\tsudo dnf config-manager --set-enabled '*' # enable all - probably not what you want" 873*abd61d1fSMauro Carvalho Chehab 874*abd61d1fSMauro Carvalho Chehab if self.pdf: 875*abd61d1fSMauro Carvalho Chehab pdf_pkgs = [ 876*abd61d1fSMauro Carvalho Chehab "/usr/share/fonts/google-noto-cjk/NotoSansCJK-Regular.ttc", 877*abd61d1fSMauro Carvalho Chehab "/usr/share/fonts/google-noto-sans-cjk-fonts/NotoSansCJK-Regular.ttc", 878*abd61d1fSMauro Carvalho Chehab ] 879*abd61d1fSMauro Carvalho Chehab 880*abd61d1fSMauro Carvalho Chehab self.check_missing_file(pdf_pkgs, noto_sans_redhat, DepManager.PDF_MANDATORY) 881*abd61d1fSMauro Carvalho Chehab 882*abd61d1fSMauro Carvalho Chehab self.check_rpm_missing(fedora_tex_pkgs, DepManager.PDF_MANDATORY) 883*abd61d1fSMauro Carvalho Chehab 884*abd61d1fSMauro Carvalho Chehab self.check_missing_tex(DepManager.PDF_MANDATORY) 885*abd61d1fSMauro Carvalho Chehab 886*abd61d1fSMauro Carvalho Chehab # There's no texlive-ctex on RHEL 8 repositories. This will 887*abd61d1fSMauro Carvalho Chehab # likely affect CJK pdf build only. 888*abd61d1fSMauro Carvalho Chehab if not fedora and rel == 8: 889*abd61d1fSMauro Carvalho Chehab self.deps.del_package("texlive-ctex") 890*abd61d1fSMauro Carvalho Chehab 891*abd61d1fSMauro Carvalho Chehab return self.get_install_progs(progs, "dnf install") 892*abd61d1fSMauro Carvalho Chehab 893*abd61d1fSMauro Carvalho Chehab def give_opensuse_hints(self): 894*abd61d1fSMauro Carvalho Chehab """ 895*abd61d1fSMauro Carvalho Chehab Provide package installation hints for openSUSE-based distros 896*abd61d1fSMauro Carvalho Chehab (Leap and Tumbleweed). 897*abd61d1fSMauro Carvalho Chehab """ 898*abd61d1fSMauro Carvalho Chehab progs = { 899*abd61d1fSMauro Carvalho Chehab "Pod::Usage": "perl-Pod-Usage", 900*abd61d1fSMauro Carvalho Chehab "convert": "ImageMagick", 901*abd61d1fSMauro Carvalho Chehab "dot": "graphviz", 902*abd61d1fSMauro Carvalho Chehab "python-sphinx": "python3-sphinx", 903*abd61d1fSMauro Carvalho Chehab "virtualenv": "python3-virtualenv", 904*abd61d1fSMauro Carvalho Chehab "xelatex": "texlive-xetex-bin texlive-dejavu", 905*abd61d1fSMauro Carvalho Chehab "yaml": "python3-pyyaml", 906*abd61d1fSMauro Carvalho Chehab } 907*abd61d1fSMauro Carvalho Chehab 908*abd61d1fSMauro Carvalho Chehab suse_tex_pkgs = [ 909*abd61d1fSMauro Carvalho Chehab "texlive-babel-english", 910*abd61d1fSMauro Carvalho Chehab "texlive-caption", 911*abd61d1fSMauro Carvalho Chehab "texlive-colortbl", 912*abd61d1fSMauro Carvalho Chehab "texlive-courier", 913*abd61d1fSMauro Carvalho Chehab "texlive-dvips", 914*abd61d1fSMauro Carvalho Chehab "texlive-helvetic", 915*abd61d1fSMauro Carvalho Chehab "texlive-makeindex", 916*abd61d1fSMauro Carvalho Chehab "texlive-metafont", 917*abd61d1fSMauro Carvalho Chehab "texlive-metapost", 918*abd61d1fSMauro Carvalho Chehab "texlive-palatino", 919*abd61d1fSMauro Carvalho Chehab "texlive-preview", 920*abd61d1fSMauro Carvalho Chehab "texlive-times", 921*abd61d1fSMauro Carvalho Chehab "texlive-zapfchan", 922*abd61d1fSMauro Carvalho Chehab "texlive-zapfding", 923*abd61d1fSMauro Carvalho Chehab ] 924*abd61d1fSMauro Carvalho Chehab 925*abd61d1fSMauro Carvalho Chehab progs["latexmk"] = "texlive-latexmk-bin" 926*abd61d1fSMauro Carvalho Chehab 927*abd61d1fSMauro Carvalho Chehab match = re.search(r"(Leap)\s+(\d+).(\d)", self.system_release) 928*abd61d1fSMauro Carvalho Chehab if match: 929*abd61d1fSMauro Carvalho Chehab rel = int(match.group(2)) 930*abd61d1fSMauro Carvalho Chehab 931*abd61d1fSMauro Carvalho Chehab # Leap 15.x uses Python 3.6, which is not compatible with 932*abd61d1fSMauro Carvalho Chehab # the build system anymore. Suggest Python 3.11 933*abd61d1fSMauro Carvalho Chehab if rel == 15: 934*abd61d1fSMauro Carvalho Chehab if not self.which(self.python_cmd): 935*abd61d1fSMauro Carvalho Chehab self.check_program("python3.11", DepManager.SYSTEM_MANDATORY) 936*abd61d1fSMauro Carvalho Chehab progs["python3.11"] = "python311" 937*abd61d1fSMauro Carvalho Chehab self.recommend_python = True 938*abd61d1fSMauro Carvalho Chehab 939*abd61d1fSMauro Carvalho Chehab progs.update({ 940*abd61d1fSMauro Carvalho Chehab "python-sphinx": "python311-Sphinx python311-Sphinx-latex", 941*abd61d1fSMauro Carvalho Chehab "virtualenv": "python311-virtualenv", 942*abd61d1fSMauro Carvalho Chehab "yaml": "python311-PyYAML", 943*abd61d1fSMauro Carvalho Chehab }) 944*abd61d1fSMauro Carvalho Chehab else: 945*abd61d1fSMauro Carvalho Chehab # Tumbleweed defaults to Python 3.11 946*abd61d1fSMauro Carvalho Chehab 947*abd61d1fSMauro Carvalho Chehab progs.update({ 948*abd61d1fSMauro Carvalho Chehab "python-sphinx": "python313-Sphinx python313-Sphinx-latex", 949*abd61d1fSMauro Carvalho Chehab "virtualenv": "python313-virtualenv", 950*abd61d1fSMauro Carvalho Chehab "yaml": "python313-PyYAML", 951*abd61d1fSMauro Carvalho Chehab }) 952*abd61d1fSMauro Carvalho Chehab 953*abd61d1fSMauro Carvalho Chehab # FIXME: add support for installing CJK fonts 954*abd61d1fSMauro Carvalho Chehab # 955*abd61d1fSMauro Carvalho Chehab # I tried hard, but was unable to find a way to install 956*abd61d1fSMauro Carvalho Chehab # "Noto Sans CJK SC" on openSUSE 957*abd61d1fSMauro Carvalho Chehab 958*abd61d1fSMauro Carvalho Chehab if self.pdf: 959*abd61d1fSMauro Carvalho Chehab self.check_rpm_missing(suse_tex_pkgs, DepManager.PDF_MANDATORY) 960*abd61d1fSMauro Carvalho Chehab if self.pdf: 961*abd61d1fSMauro Carvalho Chehab self.check_missing_tex() 962*abd61d1fSMauro Carvalho Chehab 963*abd61d1fSMauro Carvalho Chehab return self.get_install_progs(progs, "zypper install --no-recommends") 964*abd61d1fSMauro Carvalho Chehab 965*abd61d1fSMauro Carvalho Chehab def give_mageia_hints(self): 966*abd61d1fSMauro Carvalho Chehab """ 967*abd61d1fSMauro Carvalho Chehab Provide package installation hints for Mageia and OpenMandriva. 968*abd61d1fSMauro Carvalho Chehab """ 969*abd61d1fSMauro Carvalho Chehab progs = { 970*abd61d1fSMauro Carvalho Chehab "Pod::Usage": "perl-Pod-Usage", 971*abd61d1fSMauro Carvalho Chehab "convert": "ImageMagick", 972*abd61d1fSMauro Carvalho Chehab "dot": "graphviz", 973*abd61d1fSMauro Carvalho Chehab "python-sphinx": "python3-sphinx", 974*abd61d1fSMauro Carvalho Chehab "rsvg-convert": "librsvg2", 975*abd61d1fSMauro Carvalho Chehab "virtualenv": "python3-virtualenv", 976*abd61d1fSMauro Carvalho Chehab "xelatex": "texlive", 977*abd61d1fSMauro Carvalho Chehab "yaml": "python3-yaml", 978*abd61d1fSMauro Carvalho Chehab } 979*abd61d1fSMauro Carvalho Chehab 980*abd61d1fSMauro Carvalho Chehab tex_pkgs = [ 981*abd61d1fSMauro Carvalho Chehab "texlive-fontsextra", 982*abd61d1fSMauro Carvalho Chehab "texlive-fonts-asian", 983*abd61d1fSMauro Carvalho Chehab "fonts-ttf-dejavu", 984*abd61d1fSMauro Carvalho Chehab ] 985*abd61d1fSMauro Carvalho Chehab 986*abd61d1fSMauro Carvalho Chehab if re.search(r"OpenMandriva", self.system_release): 987*abd61d1fSMauro Carvalho Chehab packager_cmd = "dnf install" 988*abd61d1fSMauro Carvalho Chehab noto_sans = "noto-sans-cjk-fonts" 989*abd61d1fSMauro Carvalho Chehab tex_pkgs = [ 990*abd61d1fSMauro Carvalho Chehab "texlive-collection-basic", 991*abd61d1fSMauro Carvalho Chehab "texlive-collection-langcjk", 992*abd61d1fSMauro Carvalho Chehab "texlive-collection-fontsextra", 993*abd61d1fSMauro Carvalho Chehab "texlive-collection-fontsrecommended" 994*abd61d1fSMauro Carvalho Chehab ] 995*abd61d1fSMauro Carvalho Chehab 996*abd61d1fSMauro Carvalho Chehab # Tested on OpenMandriva Lx 4.3 997*abd61d1fSMauro Carvalho Chehab progs["convert"] = "imagemagick" 998*abd61d1fSMauro Carvalho Chehab progs["yaml"] = "python-pyyaml" 999*abd61d1fSMauro Carvalho Chehab progs["python-virtualenv"] = "python-virtualenv" 1000*abd61d1fSMauro Carvalho Chehab progs["python-sphinx"] = "python-sphinx" 1001*abd61d1fSMauro Carvalho Chehab progs["xelatex"] = "texlive" 1002*abd61d1fSMauro Carvalho Chehab 1003*abd61d1fSMauro Carvalho Chehab self.check_program("python-virtualenv", DepManager.PYTHON_MANDATORY) 1004*abd61d1fSMauro Carvalho Chehab 1005*abd61d1fSMauro Carvalho Chehab # On my tests with openMandriva LX 4.0 docker image, upgraded 1006*abd61d1fSMauro Carvalho Chehab # to 4.3, python-virtualenv package is broken: it is missing 1007*abd61d1fSMauro Carvalho Chehab # ensurepip. Without it, the alternative would be to run: 1008*abd61d1fSMauro Carvalho Chehab # python3 -m venv --without-pip ~/sphinx_latest, but running 1009*abd61d1fSMauro Carvalho Chehab # pip there won't install sphinx at venv. 1010*abd61d1fSMauro Carvalho Chehab # 1011*abd61d1fSMauro Carvalho Chehab # Add a note about that. 1012*abd61d1fSMauro Carvalho Chehab 1013*abd61d1fSMauro Carvalho Chehab if not self.distro_msg: 1014*abd61d1fSMauro Carvalho Chehab self.distro_msg = \ 1015*abd61d1fSMauro Carvalho Chehab "Notes:\n"\ 1016*abd61d1fSMauro Carvalho Chehab "1. for venv, ensurepip could be broken, preventing its install method.\n" \ 1017*abd61d1fSMauro Carvalho Chehab "2. at least on OpenMandriva LX 4.3, texlive packages seem broken" 1018*abd61d1fSMauro Carvalho Chehab 1019*abd61d1fSMauro Carvalho Chehab else: 1020*abd61d1fSMauro Carvalho Chehab packager_cmd = "urpmi" 1021*abd61d1fSMauro Carvalho Chehab noto_sans = "google-noto-sans-cjk-ttc-fonts" 1022*abd61d1fSMauro Carvalho Chehab 1023*abd61d1fSMauro Carvalho Chehab progs["latexmk"] = "texlive-collection-basic" 1024*abd61d1fSMauro Carvalho Chehab 1025*abd61d1fSMauro Carvalho Chehab if self.pdf: 1026*abd61d1fSMauro Carvalho Chehab pdf_pkgs = [ 1027*abd61d1fSMauro Carvalho Chehab "/usr/share/fonts/google-noto-cjk/NotoSansCJK-Regular.ttc", 1028*abd61d1fSMauro Carvalho Chehab "/usr/share/fonts/TTF/NotoSans-Regular.ttf", 1029*abd61d1fSMauro Carvalho Chehab ] 1030*abd61d1fSMauro Carvalho Chehab 1031*abd61d1fSMauro Carvalho Chehab self.check_missing_file(pdf_pkgs, noto_sans, DepManager.PDF_MANDATORY) 1032*abd61d1fSMauro Carvalho Chehab self.check_rpm_missing(tex_pkgs, DepManager.PDF_MANDATORY) 1033*abd61d1fSMauro Carvalho Chehab 1034*abd61d1fSMauro Carvalho Chehab return self.get_install_progs(progs, packager_cmd) 1035*abd61d1fSMauro Carvalho Chehab 1036*abd61d1fSMauro Carvalho Chehab def give_arch_linux_hints(self): 1037*abd61d1fSMauro Carvalho Chehab """ 1038*abd61d1fSMauro Carvalho Chehab Provide package installation hints for ArchLinux. 1039*abd61d1fSMauro Carvalho Chehab """ 1040*abd61d1fSMauro Carvalho Chehab progs = { 1041*abd61d1fSMauro Carvalho Chehab "convert": "imagemagick", 1042*abd61d1fSMauro Carvalho Chehab "dot": "graphviz", 1043*abd61d1fSMauro Carvalho Chehab "latexmk": "texlive-core", 1044*abd61d1fSMauro Carvalho Chehab "rsvg-convert": "extra/librsvg", 1045*abd61d1fSMauro Carvalho Chehab "virtualenv": "python-virtualenv", 1046*abd61d1fSMauro Carvalho Chehab "xelatex": "texlive-xetex", 1047*abd61d1fSMauro Carvalho Chehab "yaml": "python-yaml", 1048*abd61d1fSMauro Carvalho Chehab } 1049*abd61d1fSMauro Carvalho Chehab 1050*abd61d1fSMauro Carvalho Chehab archlinux_tex_pkgs = [ 1051*abd61d1fSMauro Carvalho Chehab "texlive-basic", 1052*abd61d1fSMauro Carvalho Chehab "texlive-binextra", 1053*abd61d1fSMauro Carvalho Chehab "texlive-core", 1054*abd61d1fSMauro Carvalho Chehab "texlive-fontsrecommended", 1055*abd61d1fSMauro Carvalho Chehab "texlive-langchinese", 1056*abd61d1fSMauro Carvalho Chehab "texlive-langcjk", 1057*abd61d1fSMauro Carvalho Chehab "texlive-latexextra", 1058*abd61d1fSMauro Carvalho Chehab "ttf-dejavu", 1059*abd61d1fSMauro Carvalho Chehab ] 1060*abd61d1fSMauro Carvalho Chehab 1061*abd61d1fSMauro Carvalho Chehab if self.pdf: 1062*abd61d1fSMauro Carvalho Chehab self.check_pacman_missing(archlinux_tex_pkgs, 1063*abd61d1fSMauro Carvalho Chehab DepManager.PDF_MANDATORY) 1064*abd61d1fSMauro Carvalho Chehab 1065*abd61d1fSMauro Carvalho Chehab self.check_missing_file(["/usr/share/fonts/noto-cjk/NotoSansCJK-Regular.ttc"], 1066*abd61d1fSMauro Carvalho Chehab "noto-fonts-cjk", 1067*abd61d1fSMauro Carvalho Chehab DepManager.PDF_MANDATORY) 1068*abd61d1fSMauro Carvalho Chehab 1069*abd61d1fSMauro Carvalho Chehab 1070*abd61d1fSMauro Carvalho Chehab return self.get_install_progs(progs, "pacman -S") 1071*abd61d1fSMauro Carvalho Chehab 1072*abd61d1fSMauro Carvalho Chehab def give_gentoo_hints(self): 1073*abd61d1fSMauro Carvalho Chehab """ 1074*abd61d1fSMauro Carvalho Chehab Provide package installation hints for Gentoo. 1075*abd61d1fSMauro Carvalho Chehab """ 1076*abd61d1fSMauro Carvalho Chehab texlive_deps = [ 1077*abd61d1fSMauro Carvalho Chehab "dev-texlive/texlive-fontsrecommended", 1078*abd61d1fSMauro Carvalho Chehab "dev-texlive/texlive-latexextra", 1079*abd61d1fSMauro Carvalho Chehab "dev-texlive/texlive-xetex", 1080*abd61d1fSMauro Carvalho Chehab "media-fonts/dejavu", 1081*abd61d1fSMauro Carvalho Chehab ] 1082*abd61d1fSMauro Carvalho Chehab 1083*abd61d1fSMauro Carvalho Chehab progs = { 1084*abd61d1fSMauro Carvalho Chehab "convert": "media-gfx/imagemagick", 1085*abd61d1fSMauro Carvalho Chehab "dot": "media-gfx/graphviz", 1086*abd61d1fSMauro Carvalho Chehab "rsvg-convert": "gnome-base/librsvg", 1087*abd61d1fSMauro Carvalho Chehab "virtualenv": "dev-python/virtualenv", 1088*abd61d1fSMauro Carvalho Chehab "xelatex": " ".join(texlive_deps), 1089*abd61d1fSMauro Carvalho Chehab "yaml": "dev-python/pyyaml", 1090*abd61d1fSMauro Carvalho Chehab "python-sphinx": "dev-python/sphinx", 1091*abd61d1fSMauro Carvalho Chehab } 1092*abd61d1fSMauro Carvalho Chehab 1093*abd61d1fSMauro Carvalho Chehab if self.pdf: 1094*abd61d1fSMauro Carvalho Chehab pdf_pkgs = { 1095*abd61d1fSMauro Carvalho Chehab "media-fonts/dejavu": [ 1096*abd61d1fSMauro Carvalho Chehab "/usr/share/fonts/dejavu/DejaVuSans.ttf", 1097*abd61d1fSMauro Carvalho Chehab ], 1098*abd61d1fSMauro Carvalho Chehab "media-fonts/noto-cjk": [ 1099*abd61d1fSMauro Carvalho Chehab "/usr/share/fonts/noto-cjk/NotoSansCJKsc-Regular.otf", 1100*abd61d1fSMauro Carvalho Chehab "/usr/share/fonts/noto-cjk/NotoSerifCJK-Regular.ttc", 1101*abd61d1fSMauro Carvalho Chehab ], 1102*abd61d1fSMauro Carvalho Chehab } 1103*abd61d1fSMauro Carvalho Chehab for package, files in pdf_pkgs.items(): 1104*abd61d1fSMauro Carvalho Chehab self.check_missing_file(files, package, DepManager.PDF_MANDATORY) 1105*abd61d1fSMauro Carvalho Chehab 1106*abd61d1fSMauro Carvalho Chehab # Handling dependencies is a nightmare, as Gentoo refuses to emerge 1107*abd61d1fSMauro Carvalho Chehab # some packages if there's no package.use file describing them. 1108*abd61d1fSMauro Carvalho Chehab # To make it worse, compilation flags shall also be present there 1109*abd61d1fSMauro Carvalho Chehab # for some packages. If USE is not perfect, error/warning messages 1110*abd61d1fSMauro Carvalho Chehab # like those are shown: 1111*abd61d1fSMauro Carvalho Chehab # 1112*abd61d1fSMauro Carvalho Chehab # !!! The following binary packages have been ignored due to non matching USE: 1113*abd61d1fSMauro Carvalho Chehab # 1114*abd61d1fSMauro Carvalho Chehab # =media-gfx/graphviz-12.2.1-r1 X pdf -python_single_target_python3_13 qt6 svg 1115*abd61d1fSMauro Carvalho Chehab # =media-gfx/graphviz-12.2.1-r1 X pdf python_single_target_python3_12 -python_single_target_python3_13 qt6 svg 1116*abd61d1fSMauro Carvalho Chehab # =media-gfx/graphviz-12.2.1-r1 X pdf qt6 svg 1117*abd61d1fSMauro Carvalho Chehab # =media-gfx/graphviz-12.2.1-r1 X pdf -python_single_target_python3_10 qt6 svg 1118*abd61d1fSMauro Carvalho Chehab # =media-gfx/graphviz-12.2.1-r1 X pdf -python_single_target_python3_10 python_single_target_python3_12 -python_single_target_python3_13 qt6 svg 1119*abd61d1fSMauro Carvalho Chehab # =media-fonts/noto-cjk-20190416 X 1120*abd61d1fSMauro Carvalho Chehab # =app-text/texlive-core-2024-r1 X cjk -xetex 1121*abd61d1fSMauro Carvalho Chehab # =app-text/texlive-core-2024-r1 X -xetex 1122*abd61d1fSMauro Carvalho Chehab # =app-text/texlive-core-2024-r1 -xetex 1123*abd61d1fSMauro Carvalho Chehab # =dev-libs/zziplib-0.13.79-r1 sdl 1124*abd61d1fSMauro Carvalho Chehab # 1125*abd61d1fSMauro Carvalho Chehab # And will ignore such packages, installing the remaining ones. That 1126*abd61d1fSMauro Carvalho Chehab # affects mostly the image extension and PDF generation. 1127*abd61d1fSMauro Carvalho Chehab 1128*abd61d1fSMauro Carvalho Chehab # Package dependencies and the minimal needed args: 1129*abd61d1fSMauro Carvalho Chehab portages = { 1130*abd61d1fSMauro Carvalho Chehab "graphviz": "media-gfx/graphviz", 1131*abd61d1fSMauro Carvalho Chehab "imagemagick": "media-gfx/imagemagick", 1132*abd61d1fSMauro Carvalho Chehab "media-libs": "media-libs/harfbuzz icu", 1133*abd61d1fSMauro Carvalho Chehab "media-fonts": "media-fonts/noto-cjk", 1134*abd61d1fSMauro Carvalho Chehab "texlive": "app-text/texlive-core xetex", 1135*abd61d1fSMauro Carvalho Chehab "zziblib": "dev-libs/zziplib sdl", 1136*abd61d1fSMauro Carvalho Chehab } 1137*abd61d1fSMauro Carvalho Chehab 1138*abd61d1fSMauro Carvalho Chehab extra_cmds = "" 1139*abd61d1fSMauro Carvalho Chehab if not self.distro_msg: 1140*abd61d1fSMauro Carvalho Chehab self.distro_msg = "Note: Gentoo requires package.use to be adjusted before emerging packages" 1141*abd61d1fSMauro Carvalho Chehab 1142*abd61d1fSMauro Carvalho Chehab use_base = "/etc/portage/package.use" 1143*abd61d1fSMauro Carvalho Chehab files = glob(f"{use_base}/*") 1144*abd61d1fSMauro Carvalho Chehab 1145*abd61d1fSMauro Carvalho Chehab for fname, portage in portages.items(): 1146*abd61d1fSMauro Carvalho Chehab install = False 1147*abd61d1fSMauro Carvalho Chehab 1148*abd61d1fSMauro Carvalho Chehab while install is False: 1149*abd61d1fSMauro Carvalho Chehab if not files: 1150*abd61d1fSMauro Carvalho Chehab # No files under package.usage. Install all 1151*abd61d1fSMauro Carvalho Chehab install = True 1152*abd61d1fSMauro Carvalho Chehab break 1153*abd61d1fSMauro Carvalho Chehab 1154*abd61d1fSMauro Carvalho Chehab args = portage.split(" ") 1155*abd61d1fSMauro Carvalho Chehab 1156*abd61d1fSMauro Carvalho Chehab name = args.pop(0) 1157*abd61d1fSMauro Carvalho Chehab 1158*abd61d1fSMauro Carvalho Chehab cmd = ["grep", "-l", "-E", rf"^{name}\b" ] + files 1159*abd61d1fSMauro Carvalho Chehab result = self.run(cmd, stdout=subprocess.PIPE, text=True) 1160*abd61d1fSMauro Carvalho Chehab if result.returncode or not result.stdout.strip(): 1161*abd61d1fSMauro Carvalho Chehab # File containing portage name not found 1162*abd61d1fSMauro Carvalho Chehab install = True 1163*abd61d1fSMauro Carvalho Chehab break 1164*abd61d1fSMauro Carvalho Chehab 1165*abd61d1fSMauro Carvalho Chehab # Ensure that needed USE flags are present 1166*abd61d1fSMauro Carvalho Chehab if args: 1167*abd61d1fSMauro Carvalho Chehab match_fname = result.stdout.strip() 1168*abd61d1fSMauro Carvalho Chehab with open(match_fname, 'r', encoding='utf8', 1169*abd61d1fSMauro Carvalho Chehab errors='backslashreplace') as fp: 1170*abd61d1fSMauro Carvalho Chehab for line in fp: 1171*abd61d1fSMauro Carvalho Chehab for arg in args: 1172*abd61d1fSMauro Carvalho Chehab if arg.startswith("-"): 1173*abd61d1fSMauro Carvalho Chehab continue 1174*abd61d1fSMauro Carvalho Chehab 1175*abd61d1fSMauro Carvalho Chehab if not re.search(rf"\s*{arg}\b", line): 1176*abd61d1fSMauro Carvalho Chehab # Needed file argument not found 1177*abd61d1fSMauro Carvalho Chehab install = True 1178*abd61d1fSMauro Carvalho Chehab break 1179*abd61d1fSMauro Carvalho Chehab 1180*abd61d1fSMauro Carvalho Chehab # Everything looks ok, don't install 1181*abd61d1fSMauro Carvalho Chehab break 1182*abd61d1fSMauro Carvalho Chehab 1183*abd61d1fSMauro Carvalho Chehab # emit a code to setup missing USE 1184*abd61d1fSMauro Carvalho Chehab if install: 1185*abd61d1fSMauro Carvalho Chehab extra_cmds += (f"sudo su -c 'echo \"{portage}\" > {use_base}/{fname}'\n") 1186*abd61d1fSMauro Carvalho Chehab 1187*abd61d1fSMauro Carvalho Chehab # Now, we can use emerge and let it respect USE 1188*abd61d1fSMauro Carvalho Chehab return self.get_install_progs(progs, 1189*abd61d1fSMauro Carvalho Chehab "emerge --ask --changed-use --binpkg-respect-use=y", 1190*abd61d1fSMauro Carvalho Chehab extra_cmds) 1191*abd61d1fSMauro Carvalho Chehab 1192*abd61d1fSMauro Carvalho Chehab def get_install(self): 1193*abd61d1fSMauro Carvalho Chehab """ 1194*abd61d1fSMauro Carvalho Chehab OS-specific hints logic. Seeks for a hinter. If found, use it to 1195*abd61d1fSMauro Carvalho Chehab provide package-manager specific install commands. 1196*abd61d1fSMauro Carvalho Chehab 1197*abd61d1fSMauro Carvalho Chehab Otherwise, outputs install instructions for the meta-packages. 1198*abd61d1fSMauro Carvalho Chehab 1199*abd61d1fSMauro Carvalho Chehab Returns a string with the command to be executed to install the 1200*abd61d1fSMauro Carvalho Chehab the needed packages, if distro found. Otherwise, return just a 1201*abd61d1fSMauro Carvalho Chehab list of packages that require installation. 1202*abd61d1fSMauro Carvalho Chehab """ 1203*abd61d1fSMauro Carvalho Chehab os_hints = { 1204*abd61d1fSMauro Carvalho Chehab re.compile("Red Hat Enterprise Linux"): self.give_redhat_hints, 1205*abd61d1fSMauro Carvalho Chehab re.compile("Fedora"): self.give_redhat_hints, 1206*abd61d1fSMauro Carvalho Chehab re.compile("AlmaLinux"): self.give_redhat_hints, 1207*abd61d1fSMauro Carvalho Chehab re.compile("Amazon Linux"): self.give_redhat_hints, 1208*abd61d1fSMauro Carvalho Chehab re.compile("CentOS"): self.give_redhat_hints, 1209*abd61d1fSMauro Carvalho Chehab re.compile("openEuler"): self.give_redhat_hints, 1210*abd61d1fSMauro Carvalho Chehab re.compile("Oracle Linux Server"): self.give_redhat_hints, 1211*abd61d1fSMauro Carvalho Chehab re.compile("Rocky Linux"): self.give_redhat_hints, 1212*abd61d1fSMauro Carvalho Chehab re.compile("Springdale Open Enterprise"): self.give_redhat_hints, 1213*abd61d1fSMauro Carvalho Chehab 1214*abd61d1fSMauro Carvalho Chehab re.compile("Ubuntu"): self.give_debian_hints, 1215*abd61d1fSMauro Carvalho Chehab re.compile("Debian"): self.give_debian_hints, 1216*abd61d1fSMauro Carvalho Chehab re.compile("Devuan"): self.give_debian_hints, 1217*abd61d1fSMauro Carvalho Chehab re.compile("Kali"): self.give_debian_hints, 1218*abd61d1fSMauro Carvalho Chehab re.compile("Mint"): self.give_debian_hints, 1219*abd61d1fSMauro Carvalho Chehab 1220*abd61d1fSMauro Carvalho Chehab re.compile("openSUSE"): self.give_opensuse_hints, 1221*abd61d1fSMauro Carvalho Chehab 1222*abd61d1fSMauro Carvalho Chehab re.compile("Mageia"): self.give_mageia_hints, 1223*abd61d1fSMauro Carvalho Chehab re.compile("OpenMandriva"): self.give_mageia_hints, 1224*abd61d1fSMauro Carvalho Chehab 1225*abd61d1fSMauro Carvalho Chehab re.compile("Arch Linux"): self.give_arch_linux_hints, 1226*abd61d1fSMauro Carvalho Chehab re.compile("Gentoo"): self.give_gentoo_hints, 1227*abd61d1fSMauro Carvalho Chehab } 1228*abd61d1fSMauro Carvalho Chehab 1229*abd61d1fSMauro Carvalho Chehab # If the OS is detected, use per-OS hint logic 1230*abd61d1fSMauro Carvalho Chehab for regex, os_hint in os_hints.items(): 1231*abd61d1fSMauro Carvalho Chehab if regex.search(self.system_release): 1232*abd61d1fSMauro Carvalho Chehab return os_hint() 1233*abd61d1fSMauro Carvalho Chehab 1234*abd61d1fSMauro Carvalho Chehab # 1235*abd61d1fSMauro Carvalho Chehab # Fall-back to generic hint code for other distros 1236*abd61d1fSMauro Carvalho Chehab # That's far from ideal, specially for LaTeX dependencies. 1237*abd61d1fSMauro Carvalho Chehab # 1238*abd61d1fSMauro Carvalho Chehab progs = {"sphinx-build": "sphinx"} 1239*abd61d1fSMauro Carvalho Chehab if self.pdf: 1240*abd61d1fSMauro Carvalho Chehab self.check_missing_tex() 1241*abd61d1fSMauro Carvalho Chehab 1242*abd61d1fSMauro Carvalho Chehab self.distro_msg = \ 1243*abd61d1fSMauro Carvalho Chehab f"I don't know distro {self.system_release}.\n" \ 1244*abd61d1fSMauro Carvalho Chehab "So, I can't provide you a hint with the install procedure.\n" \ 1245*abd61d1fSMauro Carvalho Chehab "There are likely missing dependencies." 1246*abd61d1fSMauro Carvalho Chehab 1247*abd61d1fSMauro Carvalho Chehab return self.get_install_progs(progs, None) 1248*abd61d1fSMauro Carvalho Chehab 1249*abd61d1fSMauro Carvalho Chehab # 1250*abd61d1fSMauro Carvalho Chehab # Common dependencies 1251*abd61d1fSMauro Carvalho Chehab # 1252*abd61d1fSMauro Carvalho Chehab def deactivate_help(self): 1253*abd61d1fSMauro Carvalho Chehab """ 1254*abd61d1fSMauro Carvalho Chehab Print a helper message to disable a virtual environment. 1255*abd61d1fSMauro Carvalho Chehab """ 1256*abd61d1fSMauro Carvalho Chehab 1257*abd61d1fSMauro Carvalho Chehab print("\n If you want to exit the virtualenv, you can use:") 1258*abd61d1fSMauro Carvalho Chehab print("\tdeactivate") 1259*abd61d1fSMauro Carvalho Chehab 1260*abd61d1fSMauro Carvalho Chehab def get_virtenv(self): 1261*abd61d1fSMauro Carvalho Chehab """ 1262*abd61d1fSMauro Carvalho Chehab Give a hint about how to activate an already-existing virtual 1263*abd61d1fSMauro Carvalho Chehab environment containing sphinx-build. 1264*abd61d1fSMauro Carvalho Chehab 1265*abd61d1fSMauro Carvalho Chehab Returns a tuble with (activate_cmd_path, sphinx_version) with 1266*abd61d1fSMauro Carvalho Chehab the newest available virtual env. 1267*abd61d1fSMauro Carvalho Chehab """ 1268*abd61d1fSMauro Carvalho Chehab 1269*abd61d1fSMauro Carvalho Chehab cwd = os.getcwd() 1270*abd61d1fSMauro Carvalho Chehab 1271*abd61d1fSMauro Carvalho Chehab activates = [] 1272*abd61d1fSMauro Carvalho Chehab 1273*abd61d1fSMauro Carvalho Chehab # Add all sphinx prefixes with possible version numbers 1274*abd61d1fSMauro Carvalho Chehab for p in self.virtenv_prefix: 1275*abd61d1fSMauro Carvalho Chehab activates += glob(f"{cwd}/{p}[0-9]*/bin/activate") 1276*abd61d1fSMauro Carvalho Chehab 1277*abd61d1fSMauro Carvalho Chehab activates.sort(reverse=True, key=str.lower) 1278*abd61d1fSMauro Carvalho Chehab 1279*abd61d1fSMauro Carvalho Chehab # Place sphinx_latest first, if it exists 1280*abd61d1fSMauro Carvalho Chehab for p in self.virtenv_prefix: 1281*abd61d1fSMauro Carvalho Chehab activates = glob(f"{cwd}/{p}*latest/bin/activate") + activates 1282*abd61d1fSMauro Carvalho Chehab 1283*abd61d1fSMauro Carvalho Chehab ver = (0, 0, 0) 1284*abd61d1fSMauro Carvalho Chehab for f in activates: 1285*abd61d1fSMauro Carvalho Chehab # Discard too old Sphinx virtual environments 1286*abd61d1fSMauro Carvalho Chehab match = re.search(r"(\d+)\.(\d+)\.(\d+)", f) 1287*abd61d1fSMauro Carvalho Chehab if match: 1288*abd61d1fSMauro Carvalho Chehab ver = (int(match.group(1)), int(match.group(2)), int(match.group(3))) 1289*abd61d1fSMauro Carvalho Chehab 1290*abd61d1fSMauro Carvalho Chehab if ver < self.min_version: 1291*abd61d1fSMauro Carvalho Chehab continue 1292*abd61d1fSMauro Carvalho Chehab 1293*abd61d1fSMauro Carvalho Chehab sphinx_cmd = f.replace("activate", "sphinx-build") 1294*abd61d1fSMauro Carvalho Chehab if not os.path.isfile(sphinx_cmd): 1295*abd61d1fSMauro Carvalho Chehab continue 1296*abd61d1fSMauro Carvalho Chehab 1297*abd61d1fSMauro Carvalho Chehab ver = self.get_sphinx_version(sphinx_cmd) 1298*abd61d1fSMauro Carvalho Chehab 1299*abd61d1fSMauro Carvalho Chehab if not ver: 1300*abd61d1fSMauro Carvalho Chehab venv_dir = f.replace("/bin/activate", "") 1301*abd61d1fSMauro Carvalho Chehab print(f"Warning: virtual environment {venv_dir} is not working.\n" \ 1302*abd61d1fSMauro Carvalho Chehab "Python version upgrade? Remove it with:\n\n" \ 1303*abd61d1fSMauro Carvalho Chehab "\trm -rf {venv_dir}\n\n") 1304*abd61d1fSMauro Carvalho Chehab else: 1305*abd61d1fSMauro Carvalho Chehab if self.need_sphinx and ver >= self.min_version: 1306*abd61d1fSMauro Carvalho Chehab return (f, ver) 1307*abd61d1fSMauro Carvalho Chehab elif parse_version(ver) > self.cur_version: 1308*abd61d1fSMauro Carvalho Chehab return (f, ver) 1309*abd61d1fSMauro Carvalho Chehab 1310*abd61d1fSMauro Carvalho Chehab return ("", ver) 1311*abd61d1fSMauro Carvalho Chehab 1312*abd61d1fSMauro Carvalho Chehab def recommend_sphinx_upgrade(self): 1313*abd61d1fSMauro Carvalho Chehab """ 1314*abd61d1fSMauro Carvalho Chehab Check if Sphinx needs to be upgraded. 1315*abd61d1fSMauro Carvalho Chehab 1316*abd61d1fSMauro Carvalho Chehab Returns a tuple with the higest available Sphinx version if found. 1317*abd61d1fSMauro Carvalho Chehab Otherwise, returns None to indicate either that no upgrade is needed 1318*abd61d1fSMauro Carvalho Chehab or no venv was found. 1319*abd61d1fSMauro Carvalho Chehab """ 1320*abd61d1fSMauro Carvalho Chehab 1321*abd61d1fSMauro Carvalho Chehab # Avoid running sphinx-builds from venv if cur_version is good 1322*abd61d1fSMauro Carvalho Chehab if self.cur_version and self.cur_version >= RECOMMENDED_VERSION: 1323*abd61d1fSMauro Carvalho Chehab self.latest_avail_ver = self.cur_version 1324*abd61d1fSMauro Carvalho Chehab return None 1325*abd61d1fSMauro Carvalho Chehab 1326*abd61d1fSMauro Carvalho Chehab # Get the highest version from sphinx_*/bin/sphinx-build and the 1327*abd61d1fSMauro Carvalho Chehab # corresponding command to activate the venv/virtenv 1328*abd61d1fSMauro Carvalho Chehab self.activate_cmd, self.venv_ver = self.get_virtenv() 1329*abd61d1fSMauro Carvalho Chehab 1330*abd61d1fSMauro Carvalho Chehab # Store the highest version from Sphinx existing virtualenvs 1331*abd61d1fSMauro Carvalho Chehab if self.activate_cmd and self.venv_ver > self.cur_version: 1332*abd61d1fSMauro Carvalho Chehab self.latest_avail_ver = self.venv_ver 1333*abd61d1fSMauro Carvalho Chehab else: 1334*abd61d1fSMauro Carvalho Chehab if self.cur_version: 1335*abd61d1fSMauro Carvalho Chehab self.latest_avail_ver = self.cur_version 1336*abd61d1fSMauro Carvalho Chehab else: 1337*abd61d1fSMauro Carvalho Chehab self.latest_avail_ver = (0, 0, 0) 1338*abd61d1fSMauro Carvalho Chehab 1339*abd61d1fSMauro Carvalho Chehab # As we don't know package version of Sphinx, and there's no 1340*abd61d1fSMauro Carvalho Chehab # virtual environments, don't check if upgrades are needed 1341*abd61d1fSMauro Carvalho Chehab if not self.virtualenv: 1342*abd61d1fSMauro Carvalho Chehab if not self.latest_avail_ver: 1343*abd61d1fSMauro Carvalho Chehab return None 1344*abd61d1fSMauro Carvalho Chehab 1345*abd61d1fSMauro Carvalho Chehab return self.latest_avail_ver 1346*abd61d1fSMauro Carvalho Chehab 1347*abd61d1fSMauro Carvalho Chehab # Either there are already a virtual env or a new one should be created 1348*abd61d1fSMauro Carvalho Chehab self.need_pip = True 1349*abd61d1fSMauro Carvalho Chehab 1350*abd61d1fSMauro Carvalho Chehab if not self.latest_avail_ver: 1351*abd61d1fSMauro Carvalho Chehab return None 1352*abd61d1fSMauro Carvalho Chehab 1353*abd61d1fSMauro Carvalho Chehab # Return if the reason is due to an upgrade or not 1354*abd61d1fSMauro Carvalho Chehab if self.latest_avail_ver != (0, 0, 0): 1355*abd61d1fSMauro Carvalho Chehab if self.latest_avail_ver < RECOMMENDED_VERSION: 1356*abd61d1fSMauro Carvalho Chehab self.rec_sphinx_upgrade = 1 1357*abd61d1fSMauro Carvalho Chehab 1358*abd61d1fSMauro Carvalho Chehab return self.latest_avail_ver 1359*abd61d1fSMauro Carvalho Chehab 1360*abd61d1fSMauro Carvalho Chehab def recommend_package(self): 1361*abd61d1fSMauro Carvalho Chehab """ 1362*abd61d1fSMauro Carvalho Chehab Recommend installing Sphinx as a distro-specific package. 1363*abd61d1fSMauro Carvalho Chehab """ 1364*abd61d1fSMauro Carvalho Chehab 1365*abd61d1fSMauro Carvalho Chehab print("\n2) As a package with:") 1366*abd61d1fSMauro Carvalho Chehab 1367*abd61d1fSMauro Carvalho Chehab old_need = self.deps.need 1368*abd61d1fSMauro Carvalho Chehab old_optional = self.deps.optional 1369*abd61d1fSMauro Carvalho Chehab 1370*abd61d1fSMauro Carvalho Chehab self.pdf = False 1371*abd61d1fSMauro Carvalho Chehab self.deps.optional = 0 1372*abd61d1fSMauro Carvalho Chehab old_verbose = self.verbose_warn_install 1373*abd61d1fSMauro Carvalho Chehab self.verbose_warn_install = 0 1374*abd61d1fSMauro Carvalho Chehab 1375*abd61d1fSMauro Carvalho Chehab self.deps.clear_deps() 1376*abd61d1fSMauro Carvalho Chehab 1377*abd61d1fSMauro Carvalho Chehab self.deps.add_package("python-sphinx", DepManager.PYTHON_MANDATORY) 1378*abd61d1fSMauro Carvalho Chehab 1379*abd61d1fSMauro Carvalho Chehab cmd = self.get_install() 1380*abd61d1fSMauro Carvalho Chehab if cmd: 1381*abd61d1fSMauro Carvalho Chehab print(cmd) 1382*abd61d1fSMauro Carvalho Chehab 1383*abd61d1fSMauro Carvalho Chehab self.deps.need = old_need 1384*abd61d1fSMauro Carvalho Chehab self.deps.optional = old_optional 1385*abd61d1fSMauro Carvalho Chehab self.verbose_warn_install = old_verbose 1386*abd61d1fSMauro Carvalho Chehab 1387*abd61d1fSMauro Carvalho Chehab def recommend_sphinx_version(self, virtualenv_cmd): 1388*abd61d1fSMauro Carvalho Chehab """ 1389*abd61d1fSMauro Carvalho Chehab Provide recommendations for installing or upgrading Sphinx based 1390*abd61d1fSMauro Carvalho Chehab on current version. 1391*abd61d1fSMauro Carvalho Chehab 1392*abd61d1fSMauro Carvalho Chehab The logic here is complex, as it have to deal with different versions: 1393*abd61d1fSMauro Carvalho Chehab 1394*abd61d1fSMauro Carvalho Chehab - minimal supported version; 1395*abd61d1fSMauro Carvalho Chehab - minimal PDF version; 1396*abd61d1fSMauro Carvalho Chehab - recommended version. 1397*abd61d1fSMauro Carvalho Chehab 1398*abd61d1fSMauro Carvalho Chehab It also needs to work fine with both distro's package and 1399*abd61d1fSMauro Carvalho Chehab venv/virtualenv 1400*abd61d1fSMauro Carvalho Chehab """ 1401*abd61d1fSMauro Carvalho Chehab 1402*abd61d1fSMauro Carvalho Chehab if self.recommend_python: 1403*abd61d1fSMauro Carvalho Chehab cur_ver = sys.version_info[:3] 1404*abd61d1fSMauro Carvalho Chehab if cur_ver < MIN_PYTHON_VERSION: 1405*abd61d1fSMauro Carvalho Chehab print(f"\nPython version {cur_ver} is incompatible with doc build.\n" \ 1406*abd61d1fSMauro Carvalho Chehab "Please upgrade it and re-run.\n") 1407*abd61d1fSMauro Carvalho Chehab return 1408*abd61d1fSMauro Carvalho Chehab 1409*abd61d1fSMauro Carvalho Chehab # Version is OK. Nothing to do. 1410*abd61d1fSMauro Carvalho Chehab if self.cur_version != (0, 0, 0) and self.cur_version >= RECOMMENDED_VERSION: 1411*abd61d1fSMauro Carvalho Chehab return 1412*abd61d1fSMauro Carvalho Chehab 1413*abd61d1fSMauro Carvalho Chehab if self.latest_avail_ver: 1414*abd61d1fSMauro Carvalho Chehab latest_avail_ver = ver_str(self.latest_avail_ver) 1415*abd61d1fSMauro Carvalho Chehab 1416*abd61d1fSMauro Carvalho Chehab if not self.need_sphinx: 1417*abd61d1fSMauro Carvalho Chehab # sphinx-build is present and its version is >= $min_version 1418*abd61d1fSMauro Carvalho Chehab 1419*abd61d1fSMauro Carvalho Chehab # only recommend enabling a newer virtenv version if makes sense. 1420*abd61d1fSMauro Carvalho Chehab if self.latest_avail_ver and self.latest_avail_ver > self.cur_version: 1421*abd61d1fSMauro Carvalho Chehab print(f"\nYou may also use the newer Sphinx version {latest_avail_ver} with:") 1422*abd61d1fSMauro Carvalho Chehab if f"{self.virtenv_prefix}" in os.getcwd(): 1423*abd61d1fSMauro Carvalho Chehab print("\tdeactivate") 1424*abd61d1fSMauro Carvalho Chehab print(f"\t. {self.activate_cmd}") 1425*abd61d1fSMauro Carvalho Chehab self.deactivate_help() 1426*abd61d1fSMauro Carvalho Chehab return 1427*abd61d1fSMauro Carvalho Chehab 1428*abd61d1fSMauro Carvalho Chehab if self.latest_avail_ver and self.latest_avail_ver >= RECOMMENDED_VERSION: 1429*abd61d1fSMauro Carvalho Chehab return 1430*abd61d1fSMauro Carvalho Chehab 1431*abd61d1fSMauro Carvalho Chehab if not self.virtualenv: 1432*abd61d1fSMauro Carvalho Chehab # No sphinx either via package or via virtenv. As we can't 1433*abd61d1fSMauro Carvalho Chehab # Compare the versions here, just return, recommending the 1434*abd61d1fSMauro Carvalho Chehab # user to install it from the package distro. 1435*abd61d1fSMauro Carvalho Chehab if not self.latest_avail_ver or self.latest_avail_ver == (0, 0, 0): 1436*abd61d1fSMauro Carvalho Chehab return 1437*abd61d1fSMauro Carvalho Chehab 1438*abd61d1fSMauro Carvalho Chehab # User doesn't want a virtenv recommendation, but he already 1439*abd61d1fSMauro Carvalho Chehab # installed one via virtenv with a newer version. 1440*abd61d1fSMauro Carvalho Chehab # So, print commands to enable it 1441*abd61d1fSMauro Carvalho Chehab if self.latest_avail_ver > self.cur_version: 1442*abd61d1fSMauro Carvalho Chehab print(f"\nYou may also use the Sphinx virtualenv version {latest_avail_ver} with:") 1443*abd61d1fSMauro Carvalho Chehab if f"{self.virtenv_prefix}" in os.getcwd(): 1444*abd61d1fSMauro Carvalho Chehab print("\tdeactivate") 1445*abd61d1fSMauro Carvalho Chehab print(f"\t. {self.activate_cmd}") 1446*abd61d1fSMauro Carvalho Chehab self.deactivate_help() 1447*abd61d1fSMauro Carvalho Chehab return 1448*abd61d1fSMauro Carvalho Chehab print("\n") 1449*abd61d1fSMauro Carvalho Chehab else: 1450*abd61d1fSMauro Carvalho Chehab if self.need_sphinx: 1451*abd61d1fSMauro Carvalho Chehab self.deps.need += 1 1452*abd61d1fSMauro Carvalho Chehab 1453*abd61d1fSMauro Carvalho Chehab # Suggest newer versions if current ones are too old 1454*abd61d1fSMauro Carvalho Chehab if self.latest_avail_ver and self.latest_avail_ver >= self.min_version: 1455*abd61d1fSMauro Carvalho Chehab if self.latest_avail_ver >= RECOMMENDED_VERSION: 1456*abd61d1fSMauro Carvalho Chehab print(f"\nNeed to activate Sphinx (version {latest_avail_ver}) on virtualenv with:") 1457*abd61d1fSMauro Carvalho Chehab print(f"\t. {self.activate_cmd}") 1458*abd61d1fSMauro Carvalho Chehab self.deactivate_help() 1459*abd61d1fSMauro Carvalho Chehab return 1460*abd61d1fSMauro Carvalho Chehab 1461*abd61d1fSMauro Carvalho Chehab # Version is above the minimal required one, but may be 1462*abd61d1fSMauro Carvalho Chehab # below the recommended one. So, print warnings/notes 1463*abd61d1fSMauro Carvalho Chehab if self.latest_avail_ver < RECOMMENDED_VERSION: 1464*abd61d1fSMauro Carvalho Chehab print(f"Warning: It is recommended at least Sphinx version {RECOMMENDED_VERSION}.") 1465*abd61d1fSMauro Carvalho Chehab 1466*abd61d1fSMauro Carvalho Chehab # At this point, either it needs Sphinx or upgrade is recommended, 1467*abd61d1fSMauro Carvalho Chehab # both via pip 1468*abd61d1fSMauro Carvalho Chehab 1469*abd61d1fSMauro Carvalho Chehab if self.rec_sphinx_upgrade: 1470*abd61d1fSMauro Carvalho Chehab if not self.virtualenv: 1471*abd61d1fSMauro Carvalho Chehab print("Instead of install/upgrade Python Sphinx pkg, you could use pip/pypi with:\n\n") 1472*abd61d1fSMauro Carvalho Chehab else: 1473*abd61d1fSMauro Carvalho Chehab print("To upgrade Sphinx, use:\n\n") 1474*abd61d1fSMauro Carvalho Chehab else: 1475*abd61d1fSMauro Carvalho Chehab print("\nSphinx needs to be installed either:\n1) via pip/pypi with:\n") 1476*abd61d1fSMauro Carvalho Chehab 1477*abd61d1fSMauro Carvalho Chehab if not virtualenv_cmd: 1478*abd61d1fSMauro Carvalho Chehab print(" Currently not possible.\n") 1479*abd61d1fSMauro Carvalho Chehab print(" Please upgrade Python to a newer version and run this script again") 1480*abd61d1fSMauro Carvalho Chehab else: 1481*abd61d1fSMauro Carvalho Chehab print(f"\t{virtualenv_cmd} {self.virtenv_dir}") 1482*abd61d1fSMauro Carvalho Chehab print(f"\t. {self.virtenv_dir}/bin/activate") 1483*abd61d1fSMauro Carvalho Chehab print(f"\tpip install -r {self.requirement_file}") 1484*abd61d1fSMauro Carvalho Chehab self.deactivate_help() 1485*abd61d1fSMauro Carvalho Chehab 1486*abd61d1fSMauro Carvalho Chehab if self.package_supported: 1487*abd61d1fSMauro Carvalho Chehab self.recommend_package() 1488*abd61d1fSMauro Carvalho Chehab 1489*abd61d1fSMauro Carvalho Chehab print("\n" \ 1490*abd61d1fSMauro Carvalho Chehab " Please note that Sphinx currentlys produce false-positive\n" \ 1491*abd61d1fSMauro Carvalho Chehab " warnings when the same name is used for more than one type (functions,\n" \ 1492*abd61d1fSMauro Carvalho Chehab " structs, enums,...). This is known Sphinx bug. For more details, see:\n" \ 1493*abd61d1fSMauro Carvalho Chehab "\thttps://github.com/sphinx-doc/sphinx/pull/8313") 1494*abd61d1fSMauro Carvalho Chehab 1495*abd61d1fSMauro Carvalho Chehab def check_needs(self): 1496*abd61d1fSMauro Carvalho Chehab """ 1497*abd61d1fSMauro Carvalho Chehab Main method that checks needed dependencies and provides 1498*abd61d1fSMauro Carvalho Chehab recommendations. 1499*abd61d1fSMauro Carvalho Chehab """ 1500*abd61d1fSMauro Carvalho Chehab self.python_cmd = sys.executable 1501*abd61d1fSMauro Carvalho Chehab 1502*abd61d1fSMauro Carvalho Chehab # Check if Sphinx is already accessible from current environment 1503*abd61d1fSMauro Carvalho Chehab self.check_sphinx(self.conf) 1504*abd61d1fSMauro Carvalho Chehab 1505*abd61d1fSMauro Carvalho Chehab if self.system_release: 1506*abd61d1fSMauro Carvalho Chehab print(f"Detected OS: {self.system_release}.") 1507*abd61d1fSMauro Carvalho Chehab else: 1508*abd61d1fSMauro Carvalho Chehab print("Unknown OS") 1509*abd61d1fSMauro Carvalho Chehab if self.cur_version != (0, 0, 0): 1510*abd61d1fSMauro Carvalho Chehab ver = ver_str(self.cur_version) 1511*abd61d1fSMauro Carvalho Chehab print(f"Sphinx version: {ver}\n") 1512*abd61d1fSMauro Carvalho Chehab 1513*abd61d1fSMauro Carvalho Chehab # Check the type of virtual env, depending on Python version 1514*abd61d1fSMauro Carvalho Chehab virtualenv_cmd = None 1515*abd61d1fSMauro Carvalho Chehab 1516*abd61d1fSMauro Carvalho Chehab if sys.version_info < MIN_PYTHON_VERSION: 1517*abd61d1fSMauro Carvalho Chehab min_ver = ver_str(MIN_PYTHON_VERSION) 1518*abd61d1fSMauro Carvalho Chehab print(f"ERROR: at least python {min_ver} is required to build the kernel docs") 1519*abd61d1fSMauro Carvalho Chehab self.need_sphinx = 1 1520*abd61d1fSMauro Carvalho Chehab 1521*abd61d1fSMauro Carvalho Chehab self.venv_ver = self.recommend_sphinx_upgrade() 1522*abd61d1fSMauro Carvalho Chehab 1523*abd61d1fSMauro Carvalho Chehab if self.need_pip: 1524*abd61d1fSMauro Carvalho Chehab if sys.version_info < MIN_PYTHON_VERSION: 1525*abd61d1fSMauro Carvalho Chehab self.need_pip = False 1526*abd61d1fSMauro Carvalho Chehab print("Warning: python version is not supported.") 1527*abd61d1fSMauro Carvalho Chehab else: 1528*abd61d1fSMauro Carvalho Chehab virtualenv_cmd = f"{self.python_cmd} -m venv" 1529*abd61d1fSMauro Carvalho Chehab self.check_python_module("ensurepip") 1530*abd61d1fSMauro Carvalho Chehab 1531*abd61d1fSMauro Carvalho Chehab # Check for needed programs/tools 1532*abd61d1fSMauro Carvalho Chehab self.check_perl_module("Pod::Usage", DepManager.SYSTEM_MANDATORY) 1533*abd61d1fSMauro Carvalho Chehab 1534*abd61d1fSMauro Carvalho Chehab self.check_program("make", DepManager.SYSTEM_MANDATORY) 1535*abd61d1fSMauro Carvalho Chehab self.check_program("which", DepManager.SYSTEM_MANDATORY) 1536*abd61d1fSMauro Carvalho Chehab 1537*abd61d1fSMauro Carvalho Chehab self.check_program("dot", DepManager.SYSTEM_OPTIONAL) 1538*abd61d1fSMauro Carvalho Chehab self.check_program("convert", DepManager.SYSTEM_OPTIONAL) 1539*abd61d1fSMauro Carvalho Chehab 1540*abd61d1fSMauro Carvalho Chehab self.check_python_module("yaml") 1541*abd61d1fSMauro Carvalho Chehab 1542*abd61d1fSMauro Carvalho Chehab if self.pdf: 1543*abd61d1fSMauro Carvalho Chehab self.check_program("xelatex", DepManager.PDF_MANDATORY) 1544*abd61d1fSMauro Carvalho Chehab self.check_program("rsvg-convert", DepManager.PDF_MANDATORY) 1545*abd61d1fSMauro Carvalho Chehab self.check_program("latexmk", DepManager.PDF_MANDATORY) 1546*abd61d1fSMauro Carvalho Chehab 1547*abd61d1fSMauro Carvalho Chehab # Do distro-specific checks and output distro-install commands 1548*abd61d1fSMauro Carvalho Chehab cmd = self.get_install() 1549*abd61d1fSMauro Carvalho Chehab if cmd: 1550*abd61d1fSMauro Carvalho Chehab print(cmd) 1551*abd61d1fSMauro Carvalho Chehab 1552*abd61d1fSMauro Carvalho Chehab # If distro requires some special instructions, print here. 1553*abd61d1fSMauro Carvalho Chehab # Please notice that get_install() needs to be called first. 1554*abd61d1fSMauro Carvalho Chehab if self.distro_msg: 1555*abd61d1fSMauro Carvalho Chehab print("\n" + self.distro_msg) 1556*abd61d1fSMauro Carvalho Chehab 1557*abd61d1fSMauro Carvalho Chehab if not self.python_cmd: 1558*abd61d1fSMauro Carvalho Chehab if self.need == 1: 1559*abd61d1fSMauro Carvalho Chehab sys.exit("Can't build as 1 mandatory dependency is missing") 1560*abd61d1fSMauro Carvalho Chehab elif self.need: 1561*abd61d1fSMauro Carvalho Chehab sys.exit(f"Can't build as {self.need} mandatory dependencies are missing") 1562*abd61d1fSMauro Carvalho Chehab 1563*abd61d1fSMauro Carvalho Chehab # Check if sphinx-build is called sphinx-build-3 1564*abd61d1fSMauro Carvalho Chehab if self.need_symlink: 1565*abd61d1fSMauro Carvalho Chehab sphinx_path = self.which("sphinx-build-3") 1566*abd61d1fSMauro Carvalho Chehab if sphinx_path: 1567*abd61d1fSMauro Carvalho Chehab print(f"\tsudo ln -sf {sphinx_path} /usr/bin/sphinx-build\n") 1568*abd61d1fSMauro Carvalho Chehab 1569*abd61d1fSMauro Carvalho Chehab self.recommend_sphinx_version(virtualenv_cmd) 1570*abd61d1fSMauro Carvalho Chehab print("") 1571*abd61d1fSMauro Carvalho Chehab 1572*abd61d1fSMauro Carvalho Chehab if not self.deps.optional: 1573*abd61d1fSMauro Carvalho Chehab print("All optional dependencies are met.") 1574*abd61d1fSMauro Carvalho Chehab 1575*abd61d1fSMauro Carvalho Chehab if self.deps.need == 1: 1576*abd61d1fSMauro Carvalho Chehab sys.exit("Can't build as 1 mandatory dependency is missing") 1577*abd61d1fSMauro Carvalho Chehab elif self.deps.need: 1578*abd61d1fSMauro Carvalho Chehab sys.exit(f"Can't build as {self.deps.need} mandatory dependencies are missing") 1579*abd61d1fSMauro Carvalho Chehab 1580*abd61d1fSMauro Carvalho Chehab print("Needed package dependencies are met.") 1581*abd61d1fSMauro Carvalho Chehab 1582*abd61d1fSMauro Carvalho ChehabDESCRIPTION = """ 1583*abd61d1fSMauro Carvalho ChehabProcess some flags related to Sphinx installation and documentation build. 1584*abd61d1fSMauro Carvalho Chehab""" 1585*abd61d1fSMauro Carvalho Chehab 1586*abd61d1fSMauro Carvalho Chehab 1587*abd61d1fSMauro Carvalho Chehabdef main(): 1588*abd61d1fSMauro Carvalho Chehab """Main function""" 1589*abd61d1fSMauro Carvalho Chehab parser = argparse.ArgumentParser(description=DESCRIPTION) 1590*abd61d1fSMauro Carvalho Chehab 1591*abd61d1fSMauro Carvalho Chehab parser.add_argument( 1592*abd61d1fSMauro Carvalho Chehab "--no-virtualenv", 1593*abd61d1fSMauro Carvalho Chehab action="store_false", 1594*abd61d1fSMauro Carvalho Chehab dest="virtualenv", 1595*abd61d1fSMauro Carvalho Chehab help="Recommend installing Sphinx instead of using a virtualenv", 1596*abd61d1fSMauro Carvalho Chehab ) 1597*abd61d1fSMauro Carvalho Chehab 1598*abd61d1fSMauro Carvalho Chehab parser.add_argument( 1599*abd61d1fSMauro Carvalho Chehab "--no-pdf", 1600*abd61d1fSMauro Carvalho Chehab action="store_false", 1601*abd61d1fSMauro Carvalho Chehab dest="pdf", 1602*abd61d1fSMauro Carvalho Chehab help="Don't check for dependencies required to build PDF docs", 1603*abd61d1fSMauro Carvalho Chehab ) 1604*abd61d1fSMauro Carvalho Chehab 1605*abd61d1fSMauro Carvalho Chehab parser.add_argument( 1606*abd61d1fSMauro Carvalho Chehab "--version-check", 1607*abd61d1fSMauro Carvalho Chehab action="store_true", 1608*abd61d1fSMauro Carvalho Chehab dest="version_check", 1609*abd61d1fSMauro Carvalho Chehab help="If version is compatible, don't check for missing dependencies", 1610*abd61d1fSMauro Carvalho Chehab ) 1611*abd61d1fSMauro Carvalho Chehab 1612*abd61d1fSMauro Carvalho Chehab args = parser.parse_args() 1613*abd61d1fSMauro Carvalho Chehab 1614*abd61d1fSMauro Carvalho Chehab checker = SphinxDependencyChecker(args) 1615*abd61d1fSMauro Carvalho Chehab 1616*abd61d1fSMauro Carvalho Chehab checker.check_python() 1617*abd61d1fSMauro Carvalho Chehab checker.check_needs() 1618*abd61d1fSMauro Carvalho Chehab 1619*abd61d1fSMauro Carvalho Chehab# Call main if not used as module 1620*abd61d1fSMauro Carvalho Chehabif __name__ == "__main__": 1621*abd61d1fSMauro Carvalho Chehab main() 1622