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:
349
sources/poky/meta/lib/oe/path.py
Normal file
349
sources/poky/meta/lib/oe/path.py
Normal file
@@ -0,0 +1,349 @@
|
||||
#
|
||||
# Copyright OpenEmbedded Contributors
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
|
||||
import errno
|
||||
import glob
|
||||
import shutil
|
||||
import subprocess
|
||||
import os.path
|
||||
|
||||
def join(*paths):
|
||||
"""Like os.path.join but doesn't treat absolute RHS specially"""
|
||||
return os.path.normpath("/".join(paths))
|
||||
|
||||
def relative(src, dest):
|
||||
""" Return a relative path from src to dest.
|
||||
|
||||
>>> relative("/usr/bin", "/tmp/foo/bar")
|
||||
../../tmp/foo/bar
|
||||
|
||||
>>> relative("/usr/bin", "/usr/lib")
|
||||
../lib
|
||||
|
||||
>>> relative("/tmp", "/tmp/foo/bar")
|
||||
foo/bar
|
||||
"""
|
||||
|
||||
return os.path.relpath(dest, src)
|
||||
|
||||
def make_relative_symlink(path):
|
||||
""" Convert an absolute symlink to a relative one """
|
||||
if not os.path.islink(path):
|
||||
return
|
||||
link = os.readlink(path)
|
||||
if not os.path.isabs(link):
|
||||
return
|
||||
|
||||
# find the common ancestor directory
|
||||
ancestor = path
|
||||
depth = 0
|
||||
while ancestor and not link.startswith(ancestor):
|
||||
ancestor = ancestor.rpartition('/')[0]
|
||||
depth += 1
|
||||
|
||||
if not ancestor:
|
||||
print("make_relative_symlink() Error: unable to find the common ancestor of %s and its target" % path)
|
||||
return
|
||||
|
||||
base = link.partition(ancestor)[2].strip('/')
|
||||
while depth > 1:
|
||||
base = "../" + base
|
||||
depth -= 1
|
||||
|
||||
os.remove(path)
|
||||
os.symlink(base, path)
|
||||
|
||||
def replace_absolute_symlinks(basedir, d):
|
||||
"""
|
||||
Walk basedir looking for absolute symlinks and replacing them with relative ones.
|
||||
The absolute links are assumed to be relative to basedir
|
||||
(compared to make_relative_symlink above which tries to compute common ancestors
|
||||
using pattern matching instead)
|
||||
"""
|
||||
for walkroot, dirs, files in os.walk(basedir):
|
||||
for file in files + dirs:
|
||||
path = os.path.join(walkroot, file)
|
||||
if not os.path.islink(path):
|
||||
continue
|
||||
link = os.readlink(path)
|
||||
if not os.path.isabs(link):
|
||||
continue
|
||||
walkdir = os.path.dirname(path.rpartition(basedir)[2])
|
||||
base = os.path.relpath(link, walkdir)
|
||||
bb.debug(2, "Replacing absolute path %s with relative path %s" % (link, base))
|
||||
os.remove(path)
|
||||
os.symlink(base, path)
|
||||
|
||||
def format_display(path, metadata):
|
||||
""" Prepare a path for display to the user. """
|
||||
rel = relative(metadata.getVar("TOPDIR"), path)
|
||||
if len(rel) > len(path):
|
||||
return path
|
||||
else:
|
||||
return rel
|
||||
|
||||
def copytree(src, dst):
|
||||
# We could use something like shutil.copytree here but it turns out to
|
||||
# to be slow. It takes twice as long copying to an empty directory.
|
||||
# If dst already has contents performance can be 15 time slower
|
||||
# This way we also preserve hardlinks between files in the tree.
|
||||
|
||||
bb.utils.mkdirhier(dst)
|
||||
cmd = "tar --xattrs --xattrs-include='*' -cf - -S -C %s -p . | tar --xattrs --xattrs-include='*' -xf - -C %s" % (src, dst)
|
||||
subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT)
|
||||
|
||||
def copyhardlinktree(src, dst):
|
||||
"""Make a tree of hard links when possible, otherwise copy."""
|
||||
bb.utils.mkdirhier(dst)
|
||||
if os.path.isdir(src) and not len(os.listdir(src)):
|
||||
return
|
||||
|
||||
canhard = False
|
||||
testfile = None
|
||||
for root, dirs, files in os.walk(src):
|
||||
if len(files):
|
||||
testfile = os.path.join(root, files[0])
|
||||
break
|
||||
|
||||
if testfile is not None:
|
||||
try:
|
||||
os.link(testfile, os.path.join(dst, 'testfile'))
|
||||
os.unlink(os.path.join(dst, 'testfile'))
|
||||
canhard = True
|
||||
except Exception as e:
|
||||
bb.debug(2, "Hardlink test failed with " + str(e))
|
||||
|
||||
if (canhard):
|
||||
# Need to copy directories only with tar first since cp will error if two
|
||||
# writers try and create a directory at the same time
|
||||
cmd = "cd %s; find . -type d -print | tar --xattrs --xattrs-include='*' -cf - -S -C %s -p --no-recursion --files-from - | tar --xattrs --xattrs-include='*' -xhf - -C %s" % (src, src, dst)
|
||||
subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT)
|
||||
source = ''
|
||||
if os.path.isdir(src):
|
||||
if len(glob.glob('%s/.??*' % src)) > 0:
|
||||
source = './.??* '
|
||||
if len(glob.glob('%s/**' % src)) > 0:
|
||||
source += './*'
|
||||
s_dir = src
|
||||
else:
|
||||
source = src
|
||||
s_dir = os.getcwd()
|
||||
cmd = 'cp -afl --preserve=xattr %s %s' % (source, os.path.realpath(dst))
|
||||
subprocess.check_output(cmd, shell=True, cwd=s_dir, stderr=subprocess.STDOUT)
|
||||
else:
|
||||
copytree(src, dst)
|
||||
|
||||
def copyhardlink(src, dst):
|
||||
"""Make a hard link when possible, otherwise copy."""
|
||||
|
||||
try:
|
||||
os.link(src, dst)
|
||||
except OSError:
|
||||
shutil.copy(src, dst)
|
||||
|
||||
def remove(path, recurse=True):
|
||||
"""
|
||||
Equivalent to rm -f or rm -rf
|
||||
NOTE: be careful about passing paths that may contain filenames with
|
||||
wildcards in them (as opposed to passing an actual wildcarded path) -
|
||||
since we use glob.glob() to expand the path. Filenames containing
|
||||
square brackets are particularly problematic since the they may not
|
||||
actually expand to match the original filename.
|
||||
"""
|
||||
for name in glob.glob(path):
|
||||
try:
|
||||
os.unlink(name)
|
||||
except OSError as exc:
|
||||
if recurse and exc.errno == errno.EISDIR:
|
||||
shutil.rmtree(name)
|
||||
elif exc.errno != errno.ENOENT:
|
||||
raise
|
||||
|
||||
def symlink(source, destination, force=False):
|
||||
"""Create a symbolic link"""
|
||||
try:
|
||||
if force:
|
||||
remove(destination)
|
||||
os.symlink(source, destination)
|
||||
except OSError as e:
|
||||
if e.errno != errno.EEXIST or os.readlink(destination) != source:
|
||||
raise
|
||||
|
||||
def relsymlink(target, name, force=False):
|
||||
symlink(os.path.relpath(target, os.path.dirname(name)), name, force=force)
|
||||
|
||||
def find(dir, **walkoptions):
|
||||
""" Given a directory, recurses into that directory,
|
||||
returning all files as absolute paths. """
|
||||
|
||||
for root, dirs, files in os.walk(dir, **walkoptions):
|
||||
for file in files:
|
||||
yield os.path.join(root, file)
|
||||
|
||||
|
||||
## realpath() related functions
|
||||
def __is_path_below(file, root):
|
||||
return (file + os.path.sep).startswith(root)
|
||||
|
||||
def __realpath_rel(start, rel_path, root, loop_cnt, assume_dir):
|
||||
"""Calculates real path of symlink 'start' + 'rel_path' below
|
||||
'root'; no part of 'start' below 'root' must contain symlinks. """
|
||||
have_dir = True
|
||||
|
||||
for d in rel_path.split(os.path.sep):
|
||||
if not have_dir and not assume_dir:
|
||||
raise OSError(errno.ENOENT, "no such directory %s" % start)
|
||||
|
||||
if d == os.path.pardir: # '..'
|
||||
if len(start) >= len(root):
|
||||
# do not follow '..' before root
|
||||
start = os.path.dirname(start)
|
||||
else:
|
||||
# emit warning?
|
||||
pass
|
||||
else:
|
||||
(start, have_dir) = __realpath(os.path.join(start, d),
|
||||
root, loop_cnt, assume_dir)
|
||||
|
||||
assert(__is_path_below(start, root))
|
||||
|
||||
return start
|
||||
|
||||
def __realpath(file, root, loop_cnt, assume_dir):
|
||||
while os.path.islink(file) and len(file) >= len(root):
|
||||
if loop_cnt == 0:
|
||||
raise OSError(errno.ELOOP, file)
|
||||
|
||||
loop_cnt -= 1
|
||||
target = os.path.normpath(os.readlink(file))
|
||||
|
||||
if not os.path.isabs(target):
|
||||
tdir = os.path.dirname(file)
|
||||
assert(__is_path_below(tdir, root))
|
||||
else:
|
||||
tdir = root
|
||||
|
||||
file = __realpath_rel(tdir, target, root, loop_cnt, assume_dir)
|
||||
|
||||
try:
|
||||
is_dir = os.path.isdir(file)
|
||||
except:
|
||||
is_dir = false
|
||||
|
||||
return (file, is_dir)
|
||||
|
||||
def realpath(file, root, use_physdir = True, loop_cnt = 100, assume_dir = False):
|
||||
""" Returns the canonical path of 'file' with assuming a
|
||||
toplevel 'root' directory. When 'use_physdir' is set, all
|
||||
preceding path components of 'file' will be resolved first;
|
||||
this flag should be set unless it is guaranteed that there is
|
||||
no symlink in the path. When 'assume_dir' is not set, missing
|
||||
path components will raise an ENOENT error"""
|
||||
|
||||
root = os.path.normpath(root)
|
||||
file = os.path.normpath(file)
|
||||
|
||||
if not root.endswith(os.path.sep):
|
||||
# letting root end with '/' makes some things easier
|
||||
root = root + os.path.sep
|
||||
|
||||
if not __is_path_below(file, root):
|
||||
raise OSError(errno.EINVAL, "file '%s' is not below root" % file)
|
||||
|
||||
try:
|
||||
if use_physdir:
|
||||
file = __realpath_rel(root, file[(len(root) - 1):], root, loop_cnt, assume_dir)
|
||||
else:
|
||||
file = __realpath(file, root, loop_cnt, assume_dir)[0]
|
||||
except OSError as e:
|
||||
if e.errno == errno.ELOOP:
|
||||
# make ELOOP more readable; without catching it, there will
|
||||
# be printed a backtrace with 100s of OSError exceptions
|
||||
# else
|
||||
raise OSError(errno.ELOOP,
|
||||
"too much recursions while resolving '%s'; loop in '%s'" %
|
||||
(file, e.strerror))
|
||||
|
||||
raise
|
||||
|
||||
return file
|
||||
|
||||
def is_path_parent(possible_parent, *paths):
|
||||
"""
|
||||
Return True if a path is the parent of another, False otherwise.
|
||||
Multiple paths to test can be specified in which case all
|
||||
specified test paths must be under the parent in order to
|
||||
return True.
|
||||
"""
|
||||
def abs_path_trailing(pth):
|
||||
pth_abs = os.path.abspath(pth)
|
||||
if not pth_abs.endswith(os.sep):
|
||||
pth_abs += os.sep
|
||||
return pth_abs
|
||||
|
||||
possible_parent_abs = abs_path_trailing(possible_parent)
|
||||
if not paths:
|
||||
return False
|
||||
for path in paths:
|
||||
path_abs = abs_path_trailing(path)
|
||||
if not path_abs.startswith(possible_parent_abs):
|
||||
return False
|
||||
return True
|
||||
|
||||
def which_wild(pathname, path=None, mode=os.F_OK, *, reverse=False, candidates=False):
|
||||
"""Search a search path for pathname, supporting wildcards.
|
||||
|
||||
Return all paths in the specific search path matching the wildcard pattern
|
||||
in pathname, returning only the first encountered for each file. If
|
||||
candidates is True, information on all potential candidate paths are
|
||||
included.
|
||||
"""
|
||||
paths = (path or os.environ.get('PATH', os.defpath)).split(':')
|
||||
if reverse:
|
||||
paths.reverse()
|
||||
|
||||
seen, files = set(), []
|
||||
for index, element in enumerate(paths):
|
||||
if not os.path.isabs(element):
|
||||
element = os.path.abspath(element)
|
||||
|
||||
candidate = os.path.join(element, pathname)
|
||||
globbed = glob.glob(candidate)
|
||||
if globbed:
|
||||
for found_path in sorted(globbed):
|
||||
if not os.access(found_path, mode):
|
||||
continue
|
||||
rel = os.path.relpath(found_path, element)
|
||||
if rel not in seen:
|
||||
seen.add(rel)
|
||||
if candidates:
|
||||
files.append((found_path, [os.path.join(p, rel) for p in paths[:index+1]]))
|
||||
else:
|
||||
files.append(found_path)
|
||||
|
||||
return files
|
||||
|
||||
def canonicalize(paths, sep=','):
|
||||
"""Given a string with paths (separated by commas by default), expand
|
||||
each path using os.path.realpath() and return the resulting paths as a
|
||||
string (separated using the same separator a the original string).
|
||||
"""
|
||||
# Ignore paths containing "$" as they are assumed to be unexpanded bitbake
|
||||
# variables. Normally they would be ignored, e.g., when passing the paths
|
||||
# through the shell they would expand to empty strings. However, when they
|
||||
# are passed through os.path.realpath(), it will cause them to be prefixed
|
||||
# with the absolute path to the current directory and thus not be empty
|
||||
# anymore.
|
||||
#
|
||||
# Also maintain trailing slashes, as the paths may actually be used as
|
||||
# prefixes in sting compares later on, where the slashes then are important.
|
||||
canonical_paths = []
|
||||
for path in (paths or '').split(sep):
|
||||
if '$' not in path:
|
||||
trailing_slash = path.endswith('/') and '/' or ''
|
||||
canonical_paths.append(os.path.realpath(path) + trailing_slash)
|
||||
|
||||
return sep.join(canonical_paths)
|
||||
Reference in New Issue
Block a user