Complete Yocto mirror with license table for TQMa6UL (2038-compliance)
- 264 license table entries with exact download URLs (224/264 resolved) - Complete sources/ directory with all BitBake recipes - Build configuration: tqma6ul-multi-mba6ulx, spaetzle (musl) - Full traceability for Softwarefreigabeantrag - GCC 13.4.0, Linux 6.6.102, U-Boot 2023.04, musl 1.2.4 - License distribution: GPL-2.0 (24), MIT (23), GPL-2.0+ (18), BSD-3 (16)
This commit is contained in:
252
sources/poky/scripts/pythondeps
Executable file
252
sources/poky/scripts/pythondeps
Executable file
@@ -0,0 +1,252 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright OpenEmbedded Contributors
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# Determine dependencies of python scripts or available python modules in a search path.
|
||||
#
|
||||
# Given the -d argument and a filename/filenames, returns the modules imported by those files.
|
||||
# Given the -d argument and a directory/directories, recurses to find all
|
||||
# python packages and modules, returns the modules imported by these.
|
||||
# Given the -p argument and a path or paths, scans that path for available python modules/packages.
|
||||
|
||||
import argparse
|
||||
import ast
|
||||
import importlib
|
||||
from importlib import machinery
|
||||
import logging
|
||||
import os.path
|
||||
import sys
|
||||
|
||||
|
||||
logger = logging.getLogger('pythondeps')
|
||||
|
||||
suffixes = importlib.machinery.all_suffixes()
|
||||
|
||||
class PythonDepError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class DependError(PythonDepError):
|
||||
def __init__(self, path, error):
|
||||
self.path = path
|
||||
self.error = error
|
||||
PythonDepError.__init__(self, error)
|
||||
|
||||
def __str__(self):
|
||||
return "Failure determining dependencies of {}: {}".format(self.path, self.error)
|
||||
|
||||
|
||||
class ImportVisitor(ast.NodeVisitor):
|
||||
def __init__(self):
|
||||
self.imports = set()
|
||||
self.importsfrom = []
|
||||
|
||||
def visit_Import(self, node):
|
||||
for alias in node.names:
|
||||
self.imports.add(alias.name)
|
||||
|
||||
def visit_ImportFrom(self, node):
|
||||
self.importsfrom.append((node.module, [a.name for a in node.names], node.level))
|
||||
|
||||
|
||||
def walk_up(path):
|
||||
while path:
|
||||
yield path
|
||||
path, _, _ = path.rpartition(os.sep)
|
||||
|
||||
|
||||
def get_provides(path):
|
||||
path = os.path.realpath(path)
|
||||
|
||||
def get_fn_name(fn):
|
||||
for suffix in suffixes:
|
||||
if fn.endswith(suffix):
|
||||
return fn[:-len(suffix)]
|
||||
|
||||
isdir = os.path.isdir(path)
|
||||
if isdir:
|
||||
pkg_path = path
|
||||
walk_path = path
|
||||
else:
|
||||
pkg_path = get_fn_name(path)
|
||||
if pkg_path is None:
|
||||
return
|
||||
walk_path = os.path.dirname(path)
|
||||
|
||||
for curpath in walk_up(walk_path):
|
||||
if not os.path.exists(os.path.join(curpath, '__init__.py')):
|
||||
libdir = curpath
|
||||
break
|
||||
else:
|
||||
libdir = ''
|
||||
|
||||
package_relpath = pkg_path[len(libdir)+1:]
|
||||
package = '.'.join(package_relpath.split(os.sep))
|
||||
if not isdir:
|
||||
yield package, path
|
||||
else:
|
||||
if os.path.exists(os.path.join(path, '__init__.py')):
|
||||
yield package, path
|
||||
|
||||
for dirpath, dirnames, filenames in os.walk(path):
|
||||
relpath = dirpath[len(path)+1:]
|
||||
if relpath:
|
||||
if '__init__.py' not in filenames:
|
||||
dirnames[:] = []
|
||||
continue
|
||||
else:
|
||||
context = '.'.join(relpath.split(os.sep))
|
||||
if package:
|
||||
context = package + '.' + context
|
||||
yield context, dirpath
|
||||
else:
|
||||
context = package
|
||||
|
||||
for fn in filenames:
|
||||
adjusted_fn = get_fn_name(fn)
|
||||
if not adjusted_fn or adjusted_fn == '__init__':
|
||||
continue
|
||||
|
||||
fullfn = os.path.join(dirpath, fn)
|
||||
if context:
|
||||
yield context + '.' + adjusted_fn, fullfn
|
||||
else:
|
||||
yield adjusted_fn, fullfn
|
||||
|
||||
|
||||
def get_code_depends(code_string, path=None, provide=None, ispkg=False):
|
||||
try:
|
||||
code = ast.parse(code_string, path)
|
||||
except TypeError as exc:
|
||||
raise DependError(path, exc)
|
||||
except SyntaxError as exc:
|
||||
raise DependError(path, exc)
|
||||
|
||||
visitor = ImportVisitor()
|
||||
visitor.visit(code)
|
||||
for builtin_module in sys.builtin_module_names:
|
||||
if builtin_module in visitor.imports:
|
||||
visitor.imports.remove(builtin_module)
|
||||
|
||||
if provide:
|
||||
provide_elements = provide.split('.')
|
||||
if ispkg:
|
||||
provide_elements.append("__self__")
|
||||
context = '.'.join(provide_elements[:-1])
|
||||
package_path = os.path.dirname(path)
|
||||
else:
|
||||
context = None
|
||||
package_path = None
|
||||
|
||||
levelzero_importsfrom = (module for module, names, level in visitor.importsfrom
|
||||
if level == 0)
|
||||
for module in visitor.imports | set(levelzero_importsfrom):
|
||||
if context and path:
|
||||
module_basepath = os.path.join(package_path, module.replace('.', '/'))
|
||||
if os.path.exists(module_basepath):
|
||||
# Implicit relative import
|
||||
yield context + '.' + module, path
|
||||
continue
|
||||
|
||||
for suffix in suffixes:
|
||||
if os.path.exists(module_basepath + suffix):
|
||||
# Implicit relative import
|
||||
yield context + '.' + module, path
|
||||
break
|
||||
else:
|
||||
yield module, path
|
||||
else:
|
||||
yield module, path
|
||||
|
||||
for module, names, level in visitor.importsfrom:
|
||||
if level == 0:
|
||||
continue
|
||||
elif not provide:
|
||||
raise DependError("Error: ImportFrom non-zero level outside of a package: {0}".format((module, names, level)), path)
|
||||
elif level > len(provide_elements):
|
||||
raise DependError("Error: ImportFrom level exceeds package depth: {0}".format((module, names, level)), path)
|
||||
else:
|
||||
context = '.'.join(provide_elements[:-level])
|
||||
if module:
|
||||
if context:
|
||||
yield context + '.' + module, path
|
||||
else:
|
||||
yield module, path
|
||||
|
||||
|
||||
def get_file_depends(path):
|
||||
try:
|
||||
code_string = open(path, 'r').read()
|
||||
except (OSError, IOError) as exc:
|
||||
raise DependError(path, exc)
|
||||
|
||||
return get_code_depends(code_string, path)
|
||||
|
||||
|
||||
def get_depends_recursive(directory):
|
||||
directory = os.path.realpath(directory)
|
||||
|
||||
provides = dict((v, k) for k, v in get_provides(directory))
|
||||
for filename, provide in provides.items():
|
||||
if os.path.isdir(filename):
|
||||
filename = os.path.join(filename, '__init__.py')
|
||||
ispkg = True
|
||||
elif not filename.endswith('.py'):
|
||||
continue
|
||||
else:
|
||||
ispkg = False
|
||||
|
||||
with open(filename, 'r') as f:
|
||||
source = f.read()
|
||||
|
||||
depends = get_code_depends(source, filename, provide, ispkg)
|
||||
for depend, by in depends:
|
||||
yield depend, by
|
||||
|
||||
|
||||
def get_depends(path):
|
||||
if os.path.isdir(path):
|
||||
return get_depends_recursive(path)
|
||||
else:
|
||||
return get_file_depends(path)
|
||||
|
||||
|
||||
def main():
|
||||
logging.basicConfig()
|
||||
|
||||
parser = argparse.ArgumentParser(description='Determine dependencies and provided packages for python scripts/modules')
|
||||
parser.add_argument('path', nargs='+', help='full path to content to be processed')
|
||||
group = parser.add_mutually_exclusive_group()
|
||||
group.add_argument('-p', '--provides', action='store_true',
|
||||
help='given a path, display the provided python modules')
|
||||
group.add_argument('-d', '--depends', action='store_true',
|
||||
help='given a filename, display the imported python modules')
|
||||
|
||||
args = parser.parse_args()
|
||||
if args.provides:
|
||||
modules = set()
|
||||
for path in args.path:
|
||||
for provide, fn in get_provides(path):
|
||||
modules.add(provide)
|
||||
|
||||
for module in sorted(modules):
|
||||
print(module)
|
||||
elif args.depends:
|
||||
for path in args.path:
|
||||
try:
|
||||
modules = get_depends(path)
|
||||
except PythonDepError as exc:
|
||||
logger.error(str(exc))
|
||||
sys.exit(1)
|
||||
|
||||
for module, imp_by in modules:
|
||||
print("{}\t{}".format(module, imp_by))
|
||||
else:
|
||||
parser.print_help()
|
||||
sys.exit(2)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user