From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lists.gentoo.org (pigeon.gentoo.org [208.92.234.80]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by finch.gentoo.org (Postfix) with ESMTPS id 951C0158094 for ; Wed, 28 Sep 2022 07:43:00 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id 276C6E0825; Wed, 28 Sep 2022 07:42:58 +0000 (UTC) Received: from smtp.gentoo.org (woodpecker.gentoo.org [140.211.166.183]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id 0982DE0825 for ; Wed, 28 Sep 2022 07:42:57 +0000 (UTC) Received: from oystercatcher.gentoo.org (oystercatcher.gentoo.org [148.251.78.52]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id C2A3D34100C for ; Wed, 28 Sep 2022 07:42:56 +0000 (UTC) Received: from localhost.localdomain (localhost [IPv6:::1]) by oystercatcher.gentoo.org (Postfix) with ESMTP id 094C95EC for ; Wed, 28 Sep 2022 07:42:55 +0000 (UTC) From: "Mike Frysinger" To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "Mike Frysinger" Message-ID: <1664350937.b07b25dcc8ad0e518d801bc23d01fb59cc6de442.vapier@gentoo> Subject: [gentoo-commits] proj/pax-utils:master commit in: / X-VCS-Repository: proj/pax-utils X-VCS-Files: lddtree.py X-VCS-Directories: / X-VCS-Committer: vapier X-VCS-Committer-Name: Mike Frysinger X-VCS-Revision: b07b25dcc8ad0e518d801bc23d01fb59cc6de442 X-VCS-Branch: master Date: Wed, 28 Sep 2022 07:42:55 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org X-Auto-Response-Suppress: DR, RN, NRN, OOF, AutoReply X-Archives-Salt: 4a2a8963-2eac-4793-9cf9-c027aeaf51af X-Archives-Hash: 5f24a500ad7ae91f29880d334731e9aa commit: b07b25dcc8ad0e518d801bc23d01fb59cc6de442 Author: Mike Frysinger chromium org> AuthorDate: Wed Sep 28 06:03:01 2022 +0000 Commit: Mike Frysinger gentoo org> CommitDate: Wed Sep 28 07:42:17 2022 +0000 URL: https://gitweb.gentoo.org/proj/pax-utils.git/commit/?id=b07b25dc lddtree: add typing info to more places Signed-off-by: Mike Frysinger gentoo.org> lddtree.py | 87 +++++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 61 insertions(+), 26 deletions(-) diff --git a/lddtree.py b/lddtree.py index ecb353d..6939bb6 100755 --- a/lddtree.py +++ b/lddtree.py @@ -48,6 +48,7 @@ import mmap import os import shutil import sys +from typing import Any, Iterable, Optional, Union assert sys.version_info >= (3, 6), f'Python 3.6+ required, but found {sys.version}' @@ -60,31 +61,31 @@ from elftools.common import exceptions from elftools.elf.elffile import ELFFile -def warn(msg, prefix='warning'): +def warn(msg: Any, prefix: Optional[str] = "warning") -> None: """Write |msg| to stderr with a |prefix| before it""" print('%s: %s: %s' % (os.path.basename(sys.argv[0]), prefix, msg), file=sys.stderr) -def err(msg, status=1): +def err(msg: Any, status: Optional[int] = 1) -> None: """Write |msg| to stderr and exit with |status|""" warn(msg, prefix='error') sys.exit(status) -def dbg(debug, *args, **kwargs): +def dbg(debug: bool, *args, **kwargs) -> None: """Pass |args| and |kwargs| to print() when |debug| is True""" if debug: print(*args, **kwargs) -def bstr(buf): +def bstr(buf: Union[bytes, str]) -> str: """Decode the byte string into a string""" if isinstance(buf, str): return buf return buf.decode('utf-8') -def normpath(path): +def normpath(path: str) -> str: """Normalize a path Python's os.path.normpath() doesn't handle some cases: @@ -96,7 +97,7 @@ def normpath(path): @functools.lru_cache(maxsize=None) -def readlink(path, root, prefixed=False): +def readlink(path: str, root: str, prefixed: Optional[bool] = False) -> str: """Like os.readlink(), but relative to a |root| This does not currently handle the pathological case: @@ -124,14 +125,14 @@ def readlink(path, root, prefixed=False): return normpath((root + path) if prefixed else path) -def dedupe(items): +def dedupe(items: list[str]) -> list[str]: """Remove all duplicates from |items| (keeping order)""" - seen = {} + seen: dict[str, str] = {} return [seen.setdefault(x, x) for x in items if x not in seen] @functools.lru_cache(maxsize=None) -def interp_supports_argv0(interp) -> bool: +def interp_supports_argv0(interp: str) -> bool: """See whether |interp| supports the --argv0 option. Starting with glibc-2.33, the ldso supports --argv0 to override argv[0]. @@ -141,7 +142,12 @@ def interp_supports_argv0(interp) -> bool: return mm.find(b'--argv0') >= 0 -def GenerateLdsoWrapper(root, path, interp, libpaths=()): +def GenerateLdsoWrapper( + root: str, + path: str, + interp: str, + libpaths: Iterable[str] = (), +) -> None: """Generate a shell script wrapper which uses local ldso to run the ELF Since we cannot rely on the host glibc (or other libraries), we need to @@ -190,7 +196,12 @@ exec \\ @functools.lru_cache(maxsize=None) -def ParseLdPaths(str_ldpaths, root='', cwd=None, path=None): +def ParseLdPaths( + str_ldpaths: str, + root: str = "", + cwd: Optional[str] = None, + path: str = "", +) -> list[str]: """Parse the colon-delimited list of paths and apply ldso rules to each Note the special handling as dictated by the ldso: @@ -232,7 +243,12 @@ def ParseLdPaths(str_ldpaths, root='', cwd=None, path=None): return dedupe(ldpaths) -def ParseLdSoConf(ldso_conf, root='/', debug=False, _first=True): +def ParseLdSoConf( + ldso_conf: str, + root: str = "/", + debug: bool = False, + _first: bool = True, +) -> list[str]: """Load all the paths from a given ldso config file This should handle comments, whitespace, and "include" statements. @@ -283,7 +299,12 @@ def ParseLdSoConf(ldso_conf, root='/', debug=False, _first=True): return paths -def LoadLdpaths(root='/', cwd=None, prefix='', debug=False): +def LoadLdpaths( + root: str = "/", + cwd: Optional[str] = None, + prefix: str = "", + debug: bool = False, +) -> dict[str, list[str]]: """Load linker paths from common locations This parses the ld.so.conf and LD_LIBRARY_PATH env var. @@ -297,7 +318,7 @@ def LoadLdpaths(root='/', cwd=None, prefix='', debug=False): Returns: dict containing library paths to search """ - ldpaths = { + ldpaths: dict[str, list[str]] = { 'conf': [], 'env': [], 'interp': [], @@ -321,7 +342,7 @@ def LoadLdpaths(root='/', cwd=None, prefix='', debug=False): return ldpaths -def CompatibleELFs(elf1, elf2): +def CompatibleELFs(elf1: ELFFile, elf2: ELFFile) -> bool: """See if two ELFs are compatible This compares the aspects of the ELF to see if they're compatible: @@ -344,7 +365,13 @@ def CompatibleELFs(elf1, elf2): elf1.header['e_machine'] == elf2.header['e_machine']) -def FindLib(elf, lib, ldpaths, root='/', debug=False): +def FindLib( + elf: ELFFile, + lib: str, + ldpaths: list[str], + root: str = "/", + debug: bool = False, +) -> tuple[Optional[str], Optional[str]]: """Try to locate a |lib| that is compatible to |elf| in the given |ldpaths| Args: @@ -381,9 +408,17 @@ def FindLib(elf, lib, ldpaths, root='/', debug=False): # We abuse the _all_libs state. We probably shouldn't, but we do currently. # pylint: disable=dangerous-default-value -def ParseELF(path, root='/', cwd=None, prefix='', - ldpaths={'conf':[], 'env':[], 'interp':[]}, - display=None, debug=False, _first=True, _all_libs={}): +def ParseELF( + path: str, + root: str = "/", + cwd: Optional[str] = None, + prefix: str = "", + ldpaths={"conf": [], "env": [], "interp": []}, + display: Optional[str] = None, + debug: bool = False, + _first: bool = True, + _all_libs={}, +) -> dict[str, Any]: """Parse the ELF dependency tree of the specified file Args: @@ -522,7 +557,7 @@ def ParseELF(path, root='/', cwd=None, prefix='', 'path': fullpath, 'needed': [], } - if fullpath: + if realpath is not None: try: lret = ParseELF(realpath, root, cwd, prefix, ldpaths, display=fullpath, debug=debug, _first=False, _all_libs=_all_libs) @@ -541,7 +576,7 @@ class _NormalizePathAction(argparse.Action): setattr(namespace, self.dest, normpath(values)) -def _ActionShow(options, elf): +def _ActionShow(options: argparse.Namespace, elf: dict): """Show the dependency tree for this ELF""" def _show(lib, depth): chain_libs.append(lib) @@ -568,7 +603,7 @@ def _ActionShow(options, elf): shown_libs = set(elf['needed']) new_libs = elf['needed'][:] - chain_libs = [] + chain_libs: list[str] = [] interp = elf['interp'] if interp: lib = os.path.basename(interp) @@ -590,9 +625,9 @@ def _ActionShow(options, elf): _show(lib, 1) -def _ActionCopy(options, elf): +def _ActionCopy(options: argparse.Namespace, elf: dict): """Copy the ELF and its dependencies to a destination tree""" - def _StripRoot(path): + def _StripRoot(path: str) -> str: return path[len(options.root) - 1:] def _copy(realsrc, src, striproot=True, wrapit=False, libpaths=(), @@ -687,7 +722,7 @@ def _ActionCopy(options, elf): outdir=options.bindir) -def GetParser(): +def GetParser() -> argparse.ArgumentParser: """Get a CLI parser.""" parser = argparse.ArgumentParser( description=__doc__, @@ -758,7 +793,7 @@ def GetParser(): return parser -def main(argv): +def main(argv: list[str]) -> Optional[int]: """The main entry point!""" parser = GetParser() options = parser.parse_args(argv)