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:
8
sources/poky/bitbake/lib/bblayers/__init__.py
Normal file
8
sources/poky/bitbake/lib/bblayers/__init__.py
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# Copyright BitBake Contributors
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
|
||||
from pkgutil import extend_path
|
||||
__path__ = extend_path(__path__, __name__)
|
||||
277
sources/poky/bitbake/lib/bblayers/action.py
Normal file
277
sources/poky/bitbake/lib/bblayers/action.py
Normal file
@@ -0,0 +1,277 @@
|
||||
#
|
||||
# Copyright BitBake Contributors
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
|
||||
import fnmatch
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
from bb.cookerdata import findTopdir
|
||||
import bb.utils
|
||||
|
||||
from bblayers.common import LayerPlugin
|
||||
|
||||
logger = logging.getLogger('bitbake-layers')
|
||||
|
||||
|
||||
def plugin_init(plugins):
|
||||
return ActionPlugin()
|
||||
|
||||
|
||||
class ActionPlugin(LayerPlugin):
|
||||
def do_add_layer(self, args):
|
||||
"""Add one or more layers to bblayers.conf."""
|
||||
layerdirs = [os.path.abspath(ldir) for ldir in args.layerdir]
|
||||
|
||||
for layerdir in layerdirs:
|
||||
if not os.path.exists(layerdir):
|
||||
sys.stderr.write("Specified layer directory %s doesn't exist\n" % layerdir)
|
||||
return 1
|
||||
|
||||
layer_conf = os.path.join(layerdir, 'conf', 'layer.conf')
|
||||
if not os.path.exists(layer_conf):
|
||||
sys.stderr.write("Specified layer directory %s doesn't contain a conf/layer.conf file\n" % layerdir)
|
||||
return 1
|
||||
|
||||
bblayers_conf = os.path.join(findTopdir(),'conf', 'bblayers.conf')
|
||||
if not os.path.exists(bblayers_conf):
|
||||
sys.stderr.write("Unable to find bblayers.conf\n")
|
||||
return 1
|
||||
|
||||
# Back up bblayers.conf to tempdir before we add layers
|
||||
tempdir = tempfile.mkdtemp()
|
||||
backup = tempdir + "/bblayers.conf.bak"
|
||||
shutil.copy2(bblayers_conf, backup)
|
||||
|
||||
try:
|
||||
notadded, _ = bb.utils.edit_bblayers_conf(bblayers_conf, layerdirs, None)
|
||||
self.tinfoil.modified_files()
|
||||
if not (args.force or notadded):
|
||||
try:
|
||||
self.tinfoil.run_command('parseConfiguration')
|
||||
except (bb.tinfoil.TinfoilUIException, bb.BBHandledException):
|
||||
# Restore the back up copy of bblayers.conf
|
||||
shutil.copy2(backup, bblayers_conf)
|
||||
self.tinfoil.modified_files()
|
||||
bb.fatal("Parse failure with the specified layer added, exiting.")
|
||||
else:
|
||||
for item in notadded:
|
||||
sys.stderr.write("Specified layer %s is already in BBLAYERS\n" % item)
|
||||
finally:
|
||||
# Remove the back up copy of bblayers.conf
|
||||
shutil.rmtree(tempdir)
|
||||
|
||||
def do_remove_layer(self, args):
|
||||
"""Remove one or more layers from bblayers.conf."""
|
||||
bblayers_conf = os.path.join(findTopdir() ,'conf', 'bblayers.conf')
|
||||
if not os.path.exists(bblayers_conf):
|
||||
sys.stderr.write("Unable to find bblayers.conf\n")
|
||||
return 1
|
||||
|
||||
layerdirs = []
|
||||
for item in args.layerdir:
|
||||
if item.startswith('*'):
|
||||
layerdir = item
|
||||
elif not '/' in item:
|
||||
layerdir = '*/%s' % item
|
||||
else:
|
||||
layerdir = os.path.abspath(item)
|
||||
layerdirs.append(layerdir)
|
||||
(_, notremoved) = bb.utils.edit_bblayers_conf(bblayers_conf, None, layerdirs)
|
||||
self.tinfoil.modified_files()
|
||||
if notremoved:
|
||||
for item in notremoved:
|
||||
sys.stderr.write("No layers matching %s found in BBLAYERS\n" % item)
|
||||
return 1
|
||||
|
||||
def do_flatten(self, args):
|
||||
"""flatten layer configuration into a separate output directory.
|
||||
|
||||
Takes the specified layers (or all layers in the current layer
|
||||
configuration if none are specified) and builds a "flattened" directory
|
||||
containing the contents of all layers, with any overlayed recipes removed
|
||||
and bbappends appended to the corresponding recipes. Note that some manual
|
||||
cleanup may still be necessary afterwards, in particular:
|
||||
|
||||
* where non-recipe files (such as patches) are overwritten (the flatten
|
||||
command will show a warning for these)
|
||||
* where anything beyond the normal layer setup has been added to
|
||||
layer.conf (only the lowest priority number layer's layer.conf is used)
|
||||
* overridden/appended items from bbappends will need to be tidied up
|
||||
* when the flattened layers do not have the same directory structure (the
|
||||
flatten command should show a warning when this will cause a problem)
|
||||
|
||||
Warning: if you flatten several layers where another layer is intended to
|
||||
be used "inbetween" them (in layer priority order) such that recipes /
|
||||
bbappends in the layers interact, and then attempt to use the new output
|
||||
layer together with that other layer, you may no longer get the same
|
||||
build results (as the layer priority order has effectively changed).
|
||||
"""
|
||||
if len(args.layer) == 1:
|
||||
logger.error('If you specify layers to flatten you must specify at least two')
|
||||
return 1
|
||||
|
||||
outputdir = args.outputdir
|
||||
if os.path.exists(outputdir) and os.listdir(outputdir):
|
||||
logger.error('Directory %s exists and is non-empty, please clear it out first' % outputdir)
|
||||
return 1
|
||||
|
||||
layers = self.bblayers
|
||||
if len(args.layer) > 2:
|
||||
layernames = args.layer
|
||||
found_layernames = []
|
||||
found_layerdirs = []
|
||||
for layerdir in layers:
|
||||
layername = self.get_layer_name(layerdir)
|
||||
if layername in layernames:
|
||||
found_layerdirs.append(layerdir)
|
||||
found_layernames.append(layername)
|
||||
|
||||
for layername in layernames:
|
||||
if not layername in found_layernames:
|
||||
logger.error('Unable to find layer %s in current configuration, please run "%s show-layers" to list configured layers' % (layername, os.path.basename(sys.argv[0])))
|
||||
return
|
||||
layers = found_layerdirs
|
||||
else:
|
||||
layernames = []
|
||||
|
||||
# Ensure a specified path matches our list of layers
|
||||
def layer_path_match(path):
|
||||
for layerdir in layers:
|
||||
if path.startswith(os.path.join(layerdir, '')):
|
||||
return layerdir
|
||||
return None
|
||||
|
||||
applied_appends = []
|
||||
for layer in layers:
|
||||
overlayed = set()
|
||||
for mc in self.tinfoil.cooker.multiconfigs:
|
||||
for f in self.tinfoil.cooker.collections[mc].overlayed.keys():
|
||||
for of in self.tinfoil.cooker.collections[mc].overlayed[f]:
|
||||
if of.startswith(layer):
|
||||
overlayed.add(of)
|
||||
|
||||
logger.plain('Copying files from %s...' % layer )
|
||||
for root, dirs, files in os.walk(layer):
|
||||
if '.git' in dirs:
|
||||
dirs.remove('.git')
|
||||
if '.hg' in dirs:
|
||||
dirs.remove('.hg')
|
||||
|
||||
for f1 in files:
|
||||
f1full = os.sep.join([root, f1])
|
||||
if f1full in overlayed:
|
||||
logger.plain(' Skipping overlayed file %s' % f1full )
|
||||
else:
|
||||
ext = os.path.splitext(f1)[1]
|
||||
if ext != '.bbappend':
|
||||
fdest = f1full[len(layer):]
|
||||
fdest = os.path.normpath(os.sep.join([outputdir,fdest]))
|
||||
bb.utils.mkdirhier(os.path.dirname(fdest))
|
||||
if os.path.exists(fdest):
|
||||
if f1 == 'layer.conf' and root.endswith('/conf'):
|
||||
logger.plain(' Skipping layer config file %s' % f1full )
|
||||
continue
|
||||
else:
|
||||
logger.warning('Overwriting file %s', fdest)
|
||||
bb.utils.copyfile(f1full, fdest)
|
||||
if ext == '.bb':
|
||||
appends = set()
|
||||
for mc in self.tinfoil.cooker.multiconfigs:
|
||||
appends |= set(self.tinfoil.cooker.collections[mc].get_file_appends(f1full))
|
||||
for append in appends:
|
||||
if layer_path_match(append):
|
||||
logger.plain(' Applying append %s to %s' % (append, fdest))
|
||||
self.apply_append(append, fdest)
|
||||
applied_appends.append(append)
|
||||
|
||||
# Take care of when some layers are excluded and yet we have included bbappends for those recipes
|
||||
bbappends = set()
|
||||
for mc in self.tinfoil.cooker.multiconfigs:
|
||||
bbappends |= set(self.tinfoil.cooker.collections[mc].bbappends)
|
||||
|
||||
for b in bbappends:
|
||||
(recipename, appendname) = b
|
||||
if appendname not in applied_appends:
|
||||
first_append = None
|
||||
layer = layer_path_match(appendname)
|
||||
if layer:
|
||||
if first_append:
|
||||
self.apply_append(appendname, first_append)
|
||||
else:
|
||||
fdest = appendname[len(layer):]
|
||||
fdest = os.path.normpath(os.sep.join([outputdir,fdest]))
|
||||
bb.utils.mkdirhier(os.path.dirname(fdest))
|
||||
bb.utils.copyfile(appendname, fdest)
|
||||
first_append = fdest
|
||||
|
||||
# Get the regex for the first layer in our list (which is where the conf/layer.conf file will
|
||||
# have come from)
|
||||
first_regex = None
|
||||
layerdir = layers[0]
|
||||
for layername, pattern, regex, _ in self.tinfoil.cooker.bbfile_config_priorities:
|
||||
if regex.match(os.path.join(layerdir, 'test')):
|
||||
first_regex = regex
|
||||
break
|
||||
|
||||
if first_regex:
|
||||
# Find the BBFILES entries that match (which will have come from this conf/layer.conf file)
|
||||
bbfiles = str(self.tinfoil.config_data.getVar('BBFILES')).split()
|
||||
bbfiles_layer = []
|
||||
for item in bbfiles:
|
||||
if first_regex.match(item):
|
||||
newpath = os.path.join(outputdir, item[len(layerdir)+1:])
|
||||
bbfiles_layer.append(newpath)
|
||||
|
||||
if bbfiles_layer:
|
||||
# Check that all important layer files match BBFILES
|
||||
for root, dirs, files in os.walk(outputdir):
|
||||
for f1 in files:
|
||||
ext = os.path.splitext(f1)[1]
|
||||
if ext in ['.bb', '.bbappend']:
|
||||
f1full = os.sep.join([root, f1])
|
||||
entry_found = False
|
||||
for item in bbfiles_layer:
|
||||
if fnmatch.fnmatch(f1full, item):
|
||||
entry_found = True
|
||||
break
|
||||
if not entry_found:
|
||||
logger.warning("File %s does not match the flattened layer's BBFILES setting, you may need to edit conf/layer.conf or move the file elsewhere" % f1full)
|
||||
|
||||
self.tinfoil.modified_files()
|
||||
|
||||
|
||||
def get_file_layer(self, filename):
|
||||
layerdir = self.get_file_layerdir(filename)
|
||||
if layerdir:
|
||||
return self.get_layer_name(layerdir)
|
||||
else:
|
||||
return '?'
|
||||
|
||||
def get_file_layerdir(self, filename):
|
||||
layer = bb.utils.get_file_layer(filename, self.tinfoil.config_data)
|
||||
return self.bbfile_collections.get(layer, None)
|
||||
|
||||
def apply_append(self, appendname, recipename):
|
||||
with open(appendname, 'r') as appendfile:
|
||||
with open(recipename, 'a') as recipefile:
|
||||
recipefile.write('\n')
|
||||
recipefile.write('##### bbappended from %s #####\n' % self.get_file_layer(appendname))
|
||||
recipefile.writelines(appendfile.readlines())
|
||||
|
||||
def register_commands(self, sp):
|
||||
parser_add_layer = self.add_command(sp, 'add-layer', self.do_add_layer, parserecipes=False)
|
||||
parser_add_layer.add_argument('layerdir', nargs='+', help='Layer directory/directories to add')
|
||||
|
||||
parser_remove_layer = self.add_command(sp, 'remove-layer', self.do_remove_layer, parserecipes=False)
|
||||
parser_remove_layer.add_argument('layerdir', nargs='+', help='Layer directory/directories to remove (wildcards allowed, enclose in quotes to avoid shell expansion)')
|
||||
parser_remove_layer.set_defaults(func=self.do_remove_layer)
|
||||
|
||||
parser_flatten = self.add_command(sp, 'flatten', self.do_flatten)
|
||||
parser_flatten.add_argument('layer', nargs='*', help='Optional layer(s) to flatten (otherwise all are flattened)')
|
||||
parser_flatten.add_argument('outputdir', help='Output directory')
|
||||
39
sources/poky/bitbake/lib/bblayers/common.py
Normal file
39
sources/poky/bitbake/lib/bblayers/common.py
Normal file
@@ -0,0 +1,39 @@
|
||||
#
|
||||
# Copyright BitBake Contributors
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
import os
|
||||
|
||||
logger = logging.getLogger('bitbake-layers')
|
||||
|
||||
|
||||
class LayerPlugin():
|
||||
def __init__(self):
|
||||
self.tinfoil = None
|
||||
self.bblayers = []
|
||||
|
||||
def tinfoil_init(self, tinfoil):
|
||||
self.tinfoil = tinfoil
|
||||
self.bblayers = (self.tinfoil.config_data.getVar('BBLAYERS') or "").split()
|
||||
layerconfs = self.tinfoil.config_data.varhistory.get_variable_items_files('BBFILE_COLLECTIONS')
|
||||
self.bbfile_collections = {layer: os.path.dirname(os.path.dirname(path)) for layer, path in layerconfs.items()}
|
||||
|
||||
@staticmethod
|
||||
def add_command(subparsers, cmdname, function, parserecipes=True, *args, **kwargs):
|
||||
"""Convert docstring for function to help."""
|
||||
docsplit = function.__doc__.splitlines()
|
||||
help = docsplit[0]
|
||||
if len(docsplit) > 1:
|
||||
desc = '\n'.join(docsplit[1:])
|
||||
else:
|
||||
desc = help
|
||||
subparser = subparsers.add_parser(cmdname, *args, help=help, description=desc, formatter_class=argparse.RawTextHelpFormatter, **kwargs)
|
||||
subparser.set_defaults(func=function, parserecipes=parserecipes)
|
||||
return subparser
|
||||
|
||||
def get_layer_name(self, layerdir):
|
||||
return os.path.basename(layerdir.rstrip(os.sep))
|
||||
256
sources/poky/bitbake/lib/bblayers/layerindex.py
Normal file
256
sources/poky/bitbake/lib/bblayers/layerindex.py
Normal file
@@ -0,0 +1,256 @@
|
||||
#
|
||||
# Copyright BitBake Contributors
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
|
||||
import layerindexlib
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from bblayers.action import ActionPlugin
|
||||
|
||||
logger = logging.getLogger('bitbake-layers')
|
||||
|
||||
|
||||
def plugin_init(plugins):
|
||||
return LayerIndexPlugin()
|
||||
|
||||
|
||||
class LayerIndexPlugin(ActionPlugin):
|
||||
"""Subcommands for interacting with the layer index.
|
||||
|
||||
This class inherits ActionPlugin to get do_add_layer.
|
||||
"""
|
||||
|
||||
def get_fetch_layer(self, fetchdir, url, subdir, fetch_layer, branch, shallow=False):
|
||||
layername = self.get_layer_name(url)
|
||||
if os.path.splitext(layername)[1] == '.git':
|
||||
layername = os.path.splitext(layername)[0]
|
||||
repodir = os.path.join(fetchdir, layername)
|
||||
layerdir = os.path.join(repodir, subdir)
|
||||
if not os.path.exists(repodir):
|
||||
if fetch_layer:
|
||||
cmd = ['git', 'clone']
|
||||
if shallow:
|
||||
cmd.extend(['--depth', '1'])
|
||||
if branch:
|
||||
cmd.extend(['-b' , branch])
|
||||
cmd.extend([url, repodir])
|
||||
result = subprocess.call(cmd)
|
||||
if result:
|
||||
logger.error("Failed to download %s (%s)" % (url, branch))
|
||||
return None, None, None
|
||||
else:
|
||||
return subdir, layername, layerdir
|
||||
else:
|
||||
logger.plain("Repository %s needs to be fetched" % url)
|
||||
return subdir, layername, layerdir
|
||||
elif os.path.exists(repodir) and branch:
|
||||
"""
|
||||
If the repo is already cloned, ensure it is on the correct branch,
|
||||
switching branches if necessary and possible.
|
||||
"""
|
||||
base_cmd = ['git', '--git-dir=%s/.git' % repodir, '--work-tree=%s' % repodir]
|
||||
cmd = base_cmd + ['branch']
|
||||
completed_proc = subprocess.run(cmd, text=True, capture_output=True)
|
||||
if completed_proc.returncode:
|
||||
logger.error("Unable to validate repo %s (%s)" % (repodir, stderr))
|
||||
return None, None, None
|
||||
else:
|
||||
if branch != completed_proc.stdout[2:-1]:
|
||||
cmd = base_cmd + ['status', '--short']
|
||||
completed_proc = subprocess.run(cmd, text=True, capture_output=True)
|
||||
if completed_proc.stdout.count('\n') != 0:
|
||||
logger.warning("There are uncommitted changes in repo %s" % repodir)
|
||||
cmd = base_cmd + ['checkout', branch]
|
||||
completed_proc = subprocess.run(cmd, text=True, capture_output=True)
|
||||
if completed_proc.returncode:
|
||||
# Could be due to original shallow clone on a different branch for example
|
||||
logger.error("Unable to automatically switch %s to desired branch '%s' (%s)"
|
||||
% (repodir, branch, completed_proc.stderr))
|
||||
return None, None, None
|
||||
return subdir, layername, layerdir
|
||||
elif os.path.exists(layerdir):
|
||||
return subdir, layername, layerdir
|
||||
else:
|
||||
logger.error("%s is not in %s" % (url, subdir))
|
||||
return None, None, None
|
||||
|
||||
def do_layerindex_fetch(self, args):
|
||||
"""Fetches a layer from a layer index along with its dependent layers, and adds them to conf/bblayers.conf.
|
||||
"""
|
||||
|
||||
def _construct_url(baseurls, branches):
|
||||
urls = []
|
||||
for baseurl in baseurls:
|
||||
if baseurl[-1] != '/':
|
||||
baseurl += '/'
|
||||
|
||||
if not baseurl.startswith('cooker'):
|
||||
baseurl += "api/"
|
||||
|
||||
if branches:
|
||||
baseurl += ";branch=%s" % ','.join(branches)
|
||||
|
||||
urls.append(baseurl)
|
||||
|
||||
return urls
|
||||
|
||||
|
||||
# Set the default...
|
||||
if args.branch:
|
||||
branches = [args.branch]
|
||||
else:
|
||||
branches = (self.tinfoil.config_data.getVar('LAYERSERIES_CORENAMES') or 'master').split()
|
||||
logger.debug('Trying branches: %s' % branches)
|
||||
|
||||
ignore_layers = []
|
||||
if args.ignore:
|
||||
ignore_layers.extend(args.ignore.split(','))
|
||||
|
||||
# Load the cooker DB
|
||||
cookerIndex = layerindexlib.LayerIndex(self.tinfoil.config_data)
|
||||
cookerIndex.load_layerindex('cooker://', load='layerDependencies')
|
||||
|
||||
# Fast path, check if we already have what has been requested!
|
||||
(dependencies, invalidnames) = cookerIndex.find_dependencies(names=args.layername, ignores=ignore_layers)
|
||||
if not args.show_only and not invalidnames:
|
||||
logger.plain("You already have the requested layer(s): %s" % args.layername)
|
||||
return 0
|
||||
|
||||
# The information to show is already in the cookerIndex
|
||||
if invalidnames:
|
||||
# General URL to use to access the layer index
|
||||
# While there is ONE right now, we're expect users could enter several
|
||||
apiurl = self.tinfoil.config_data.getVar('BBLAYERS_LAYERINDEX_URL').split()
|
||||
if not apiurl:
|
||||
logger.error("Cannot get BBLAYERS_LAYERINDEX_URL")
|
||||
return 1
|
||||
|
||||
remoteIndex = layerindexlib.LayerIndex(self.tinfoil.config_data)
|
||||
|
||||
for remoteurl in _construct_url(apiurl, branches):
|
||||
logger.plain("Loading %s..." % remoteurl)
|
||||
remoteIndex.load_layerindex(remoteurl)
|
||||
|
||||
if remoteIndex.is_empty():
|
||||
logger.error("Remote layer index %s is empty for branches %s" % (apiurl, branches))
|
||||
return 1
|
||||
|
||||
lIndex = cookerIndex + remoteIndex
|
||||
|
||||
(dependencies, invalidnames) = lIndex.find_dependencies(names=args.layername, ignores=ignore_layers)
|
||||
|
||||
if invalidnames:
|
||||
for invaluename in invalidnames:
|
||||
logger.error('Layer "%s" not found in layer index' % invaluename)
|
||||
return 1
|
||||
|
||||
logger.plain("%s %s %s" % ("Layer".ljust(49), "Git repository (branch)".ljust(54), "Subdirectory"))
|
||||
logger.plain('=' * 125)
|
||||
|
||||
for deplayerbranch in dependencies:
|
||||
layerBranch = dependencies[deplayerbranch][0]
|
||||
|
||||
# TODO: Determine display behavior
|
||||
# This is the local content, uncomment to hide local
|
||||
# layers from the display.
|
||||
#if layerBranch.index.config['TYPE'] == 'cooker':
|
||||
# continue
|
||||
|
||||
layerDeps = dependencies[deplayerbranch][1:]
|
||||
|
||||
requiredby = []
|
||||
recommendedby = []
|
||||
for dep in layerDeps:
|
||||
if dep.required:
|
||||
requiredby.append(dep.layer.name)
|
||||
else:
|
||||
recommendedby.append(dep.layer.name)
|
||||
|
||||
logger.plain('%s %s %s' % (("%s:%s:%s" %
|
||||
(layerBranch.index.config['DESCRIPTION'],
|
||||
layerBranch.branch.name,
|
||||
layerBranch.layer.name)).ljust(50),
|
||||
("%s (%s)" % (layerBranch.layer.vcs_url,
|
||||
layerBranch.actual_branch)).ljust(55),
|
||||
layerBranch.vcs_subdir
|
||||
))
|
||||
if requiredby:
|
||||
logger.plain(' required by: %s' % ' '.join(requiredby))
|
||||
if recommendedby:
|
||||
logger.plain(' recommended by: %s' % ' '.join(recommendedby))
|
||||
|
||||
if dependencies:
|
||||
if args.fetchdir:
|
||||
fetchdir = args.fetchdir
|
||||
else:
|
||||
fetchdir = self.tinfoil.config_data.getVar('BBLAYERS_FETCH_DIR')
|
||||
if not fetchdir:
|
||||
logger.error("Cannot get BBLAYERS_FETCH_DIR")
|
||||
return 1
|
||||
|
||||
if not os.path.exists(fetchdir):
|
||||
os.makedirs(fetchdir)
|
||||
|
||||
addlayers = []
|
||||
|
||||
for deplayerbranch in dependencies:
|
||||
layerBranch = dependencies[deplayerbranch][0]
|
||||
|
||||
if layerBranch.index.config['TYPE'] == 'cooker':
|
||||
# Anything loaded via cooker is already local, skip it
|
||||
continue
|
||||
|
||||
subdir, name, layerdir = self.get_fetch_layer(fetchdir,
|
||||
layerBranch.layer.vcs_url,
|
||||
layerBranch.vcs_subdir,
|
||||
not args.show_only,
|
||||
layerBranch.actual_branch,
|
||||
args.shallow)
|
||||
if not name:
|
||||
# Error already shown
|
||||
return 1
|
||||
addlayers.append((subdir, name, layerdir))
|
||||
if not args.show_only:
|
||||
localargs = argparse.Namespace()
|
||||
localargs.layerdir = []
|
||||
localargs.force = args.force
|
||||
for subdir, name, layerdir in addlayers:
|
||||
if os.path.exists(layerdir):
|
||||
if subdir:
|
||||
logger.plain("Adding layer \"%s\" (%s) to conf/bblayers.conf" % (subdir, layerdir))
|
||||
else:
|
||||
logger.plain("Adding layer \"%s\" (%s) to conf/bblayers.conf" % (name, layerdir))
|
||||
localargs.layerdir.append(layerdir)
|
||||
else:
|
||||
break
|
||||
|
||||
if localargs.layerdir:
|
||||
self.do_add_layer(localargs)
|
||||
|
||||
def do_layerindex_show_depends(self, args):
|
||||
"""Find layer dependencies from layer index.
|
||||
"""
|
||||
args.show_only = True
|
||||
args.ignore = []
|
||||
args.fetchdir = ""
|
||||
args.shallow = True
|
||||
self.do_layerindex_fetch(args)
|
||||
|
||||
def register_commands(self, sp):
|
||||
parser_layerindex_fetch = self.add_command(sp, 'layerindex-fetch', self.do_layerindex_fetch, parserecipes=False)
|
||||
parser_layerindex_fetch.add_argument('-n', '--show-only', help='show dependencies and do nothing else', action='store_true')
|
||||
parser_layerindex_fetch.add_argument('-b', '--branch', help='branch name to fetch')
|
||||
parser_layerindex_fetch.add_argument('-s', '--shallow', help='do only shallow clones (--depth=1)', action='store_true')
|
||||
parser_layerindex_fetch.add_argument('-i', '--ignore', help='assume the specified layers do not need to be fetched/added (separate multiple layers with commas, no spaces)', metavar='LAYER')
|
||||
parser_layerindex_fetch.add_argument('-f', '--fetchdir', help='directory to fetch the layer(s) into (will be created if it does not exist)')
|
||||
parser_layerindex_fetch.add_argument('layername', nargs='+', help='layer to fetch')
|
||||
|
||||
parser_layerindex_show_depends = self.add_command(sp, 'layerindex-show-depends', self.do_layerindex_show_depends, parserecipes=False)
|
||||
parser_layerindex_show_depends.add_argument('-b', '--branch', help='branch name to fetch')
|
||||
parser_layerindex_show_depends.add_argument('layername', nargs='+', help='layer to query')
|
||||
543
sources/poky/bitbake/lib/bblayers/query.py
Normal file
543
sources/poky/bitbake/lib/bblayers/query.py
Normal file
@@ -0,0 +1,543 @@
|
||||
#
|
||||
# Copyright BitBake Contributors
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
|
||||
import collections
|
||||
import fnmatch
|
||||
import logging
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
|
||||
import bb.utils
|
||||
|
||||
from bblayers.common import LayerPlugin
|
||||
|
||||
logger = logging.getLogger('bitbake-layers')
|
||||
|
||||
|
||||
def plugin_init(plugins):
|
||||
return QueryPlugin()
|
||||
|
||||
|
||||
class QueryPlugin(LayerPlugin):
|
||||
def __init__(self):
|
||||
super(QueryPlugin, self).__init__()
|
||||
self.collection_res = {}
|
||||
|
||||
def do_show_layers(self, args):
|
||||
"""show current configured layers."""
|
||||
logger.plain("%s %s %s" % ("layer".ljust(20), "path".ljust(70), "priority"))
|
||||
logger.plain('=' * 104)
|
||||
for layer, _, regex, pri in self.tinfoil.cooker.bbfile_config_priorities:
|
||||
layerdir = self.bbfile_collections.get(layer, None)
|
||||
layername = layer
|
||||
logger.plain("%s %s %s" % (layername.ljust(20), layerdir.ljust(70), pri))
|
||||
|
||||
def version_str(self, pe, pv, pr = None):
|
||||
verstr = "%s" % pv
|
||||
if pr:
|
||||
verstr = "%s-%s" % (verstr, pr)
|
||||
if pe:
|
||||
verstr = "%s:%s" % (pe, verstr)
|
||||
return verstr
|
||||
|
||||
def do_show_overlayed(self, args):
|
||||
"""list overlayed recipes (where the same recipe exists in another layer)
|
||||
|
||||
Lists the names of overlayed recipes and the available versions in each
|
||||
layer, with the preferred version first. Note that skipped recipes that
|
||||
are overlayed will also be listed, with a " (skipped)" suffix.
|
||||
"""
|
||||
|
||||
items_listed = self.list_recipes('Overlayed recipes', None, True, args.same_version, args.filenames, False, True, None, False, None, args.mc)
|
||||
|
||||
# Check for overlayed .bbclass files
|
||||
classes = collections.defaultdict(list)
|
||||
for layerdir in self.bblayers:
|
||||
for c in ["classes-global", "classes-recipe", "classes"]:
|
||||
classdir = os.path.join(layerdir, c)
|
||||
if os.path.exists(classdir):
|
||||
for classfile in os.listdir(classdir):
|
||||
if os.path.splitext(classfile)[1] == '.bbclass':
|
||||
classes[classfile].append(classdir)
|
||||
|
||||
# Locating classes and other files is a bit more complicated than recipes -
|
||||
# layer priority is not a factor; instead BitBake uses the first matching
|
||||
# file in BBPATH, which is manipulated directly by each layer's
|
||||
# conf/layer.conf in turn, thus the order of layers in bblayers.conf is a
|
||||
# factor - however, each layer.conf is free to either prepend or append to
|
||||
# BBPATH (or indeed do crazy stuff with it). Thus the order in BBPATH might
|
||||
# not be exactly the order present in bblayers.conf either.
|
||||
bbpath = str(self.tinfoil.config_data.getVar('BBPATH'))
|
||||
overlayed_class_found = False
|
||||
for (classfile, classdirs) in classes.items():
|
||||
if len(classdirs) > 1:
|
||||
if not overlayed_class_found:
|
||||
logger.plain('=== Overlayed classes ===')
|
||||
overlayed_class_found = True
|
||||
|
||||
mainfile = bb.utils.which(bbpath, os.path.join('classes', classfile))
|
||||
if args.filenames:
|
||||
logger.plain('%s' % mainfile)
|
||||
else:
|
||||
# We effectively have to guess the layer here
|
||||
logger.plain('%s:' % classfile)
|
||||
mainlayername = '?'
|
||||
for layerdir in self.bblayers:
|
||||
classdir = os.path.join(layerdir, 'classes')
|
||||
if mainfile.startswith(classdir):
|
||||
mainlayername = self.get_layer_name(layerdir)
|
||||
logger.plain(' %s' % mainlayername)
|
||||
for classdir in classdirs:
|
||||
fullpath = os.path.join(classdir, classfile)
|
||||
if fullpath != mainfile:
|
||||
if args.filenames:
|
||||
print(' %s' % fullpath)
|
||||
else:
|
||||
print(' %s' % self.get_layer_name(os.path.dirname(classdir)))
|
||||
|
||||
if overlayed_class_found:
|
||||
items_listed = True;
|
||||
|
||||
if not items_listed:
|
||||
logger.plain('No overlayed files found.')
|
||||
|
||||
def do_show_recipes(self, args):
|
||||
"""list available recipes, showing the layer they are provided by
|
||||
|
||||
Lists the names of recipes and the available versions in each
|
||||
layer, with the preferred version first. Optionally you may specify
|
||||
pnspec to match a specified recipe name (supports wildcards). Note that
|
||||
skipped recipes will also be listed, with a " (skipped)" suffix.
|
||||
"""
|
||||
|
||||
inheritlist = args.inherits.split(',') if args.inherits else []
|
||||
if inheritlist or args.pnspec or args.multiple:
|
||||
title = 'Matching recipes:'
|
||||
else:
|
||||
title = 'Available recipes:'
|
||||
self.list_recipes(title, args.pnspec, False, False, args.filenames, args.recipes_only, args.multiple, args.layer, args.bare, inheritlist, args.mc)
|
||||
|
||||
def list_recipes(self, title, pnspec, show_overlayed_only, show_same_ver_only, show_filenames, show_recipes_only, show_multi_provider_only, selected_layer, bare, inherits, mc):
|
||||
if inherits:
|
||||
bbpath = str(self.tinfoil.config_data.getVar('BBPATH'))
|
||||
for classname in inherits:
|
||||
found = False
|
||||
for c in ["classes-global", "classes-recipe", "classes"]:
|
||||
cfile = c + '/%s.bbclass' % classname
|
||||
if bb.utils.which(bbpath, cfile, history=False):
|
||||
found = True
|
||||
break
|
||||
if not found:
|
||||
logger.error('No class named %s found in BBPATH', classname)
|
||||
sys.exit(1)
|
||||
|
||||
pkg_pn = self.tinfoil.cooker.recipecaches[mc].pkg_pn
|
||||
(latest_versions, preferred_versions, required_versions) = self.tinfoil.find_providers(mc)
|
||||
allproviders = self.tinfoil.get_all_providers(mc)
|
||||
|
||||
# Ensure we list skipped recipes
|
||||
# We are largely guessing about PN, PV and the preferred version here,
|
||||
# but we have no choice since skipped recipes are not fully parsed
|
||||
skiplist = list(self.tinfoil.cooker.skiplist_by_mc[mc].keys())
|
||||
|
||||
if mc:
|
||||
mcspec = f'mc:{mc}:'
|
||||
skiplist = [s[len(mcspec):] if s.startswith(mcspec) else s for s in skiplist]
|
||||
|
||||
for fn in skiplist:
|
||||
recipe_parts = os.path.splitext(os.path.basename(fn))[0].split('_')
|
||||
p = recipe_parts[0]
|
||||
if len(recipe_parts) > 1:
|
||||
ver = (None, recipe_parts[1], None)
|
||||
else:
|
||||
ver = (None, 'unknown', None)
|
||||
allproviders[p].append((ver, fn))
|
||||
if not p in pkg_pn:
|
||||
pkg_pn[p] = 'dummy'
|
||||
preferred_versions[p] = (ver, fn)
|
||||
|
||||
def print_item(f, pn, ver, layer, ispref):
|
||||
if not selected_layer or layer == selected_layer:
|
||||
if not bare and f in skiplist:
|
||||
skipped = ' (skipped: %s)' % self.tinfoil.cooker.skiplist_by_mc[mc][f].skipreason
|
||||
else:
|
||||
skipped = ''
|
||||
if show_filenames:
|
||||
if ispref:
|
||||
logger.plain("%s%s", f, skipped)
|
||||
else:
|
||||
logger.plain(" %s%s", f, skipped)
|
||||
elif show_recipes_only:
|
||||
if pn not in show_unique_pn:
|
||||
show_unique_pn.append(pn)
|
||||
logger.plain("%s%s", pn, skipped)
|
||||
else:
|
||||
if ispref:
|
||||
logger.plain("%s:", pn)
|
||||
logger.plain(" %s %s%s", layer.ljust(20), ver, skipped)
|
||||
|
||||
global_inherit = (self.tinfoil.config_data.getVar('INHERIT') or "").split()
|
||||
cls_re = re.compile('classes.*/')
|
||||
|
||||
preffiles = []
|
||||
show_unique_pn = []
|
||||
items_listed = False
|
||||
for p in sorted(pkg_pn):
|
||||
if pnspec:
|
||||
found=False
|
||||
for pnm in pnspec:
|
||||
if fnmatch.fnmatch(p, pnm):
|
||||
found=True
|
||||
break
|
||||
if not found:
|
||||
continue
|
||||
|
||||
if len(allproviders[p]) > 1 or not show_multi_provider_only:
|
||||
pref = preferred_versions[p]
|
||||
realfn = bb.cache.virtualfn2realfn(pref[1])
|
||||
preffile = realfn[0]
|
||||
|
||||
# We only display once per recipe, we should prefer non extended versions of the
|
||||
# recipe if present (so e.g. in OpenEmbedded, openssl rather than nativesdk-openssl
|
||||
# which would otherwise sort first).
|
||||
if realfn[1] and realfn[0] in self.tinfoil.cooker.recipecaches[mc].pkg_fn:
|
||||
continue
|
||||
|
||||
if inherits:
|
||||
matchcount = 0
|
||||
recipe_inherits = self.tinfoil.cooker_data.inherits.get(preffile, [])
|
||||
for cls in recipe_inherits:
|
||||
if cls_re.match(cls):
|
||||
continue
|
||||
classname = os.path.splitext(os.path.basename(cls))[0]
|
||||
if classname in global_inherit:
|
||||
continue
|
||||
elif classname in inherits:
|
||||
matchcount += 1
|
||||
if matchcount != len(inherits):
|
||||
# No match - skip this recipe
|
||||
continue
|
||||
|
||||
if preffile not in preffiles:
|
||||
preflayer = self.get_file_layer(preffile)
|
||||
multilayer = False
|
||||
same_ver = True
|
||||
provs = []
|
||||
for prov in allproviders[p]:
|
||||
provfile = bb.cache.virtualfn2realfn(prov[1])[0]
|
||||
provlayer = self.get_file_layer(provfile)
|
||||
provs.append((provfile, provlayer, prov[0]))
|
||||
if provlayer != preflayer:
|
||||
multilayer = True
|
||||
if prov[0] != pref[0]:
|
||||
same_ver = False
|
||||
if (multilayer or not show_overlayed_only) and (same_ver or not show_same_ver_only):
|
||||
if not items_listed:
|
||||
logger.plain('=== %s ===' % title)
|
||||
items_listed = True
|
||||
print_item(preffile, p, self.version_str(pref[0][0], pref[0][1]), preflayer, True)
|
||||
for (provfile, provlayer, provver) in provs:
|
||||
if provfile != preffile:
|
||||
print_item(provfile, p, self.version_str(provver[0], provver[1]), provlayer, False)
|
||||
# Ensure we don't show two entries for BBCLASSEXTENDed recipes
|
||||
preffiles.append(preffile)
|
||||
|
||||
return items_listed
|
||||
|
||||
def get_file_layer(self, filename):
|
||||
layerdir = self.get_file_layerdir(filename)
|
||||
if layerdir:
|
||||
return self.get_layer_name(layerdir)
|
||||
else:
|
||||
return '?'
|
||||
|
||||
def get_collection_res(self):
|
||||
if not self.collection_res:
|
||||
self.collection_res = bb.utils.get_collection_res(self.tinfoil.config_data)
|
||||
return self.collection_res
|
||||
|
||||
def get_file_layerdir(self, filename):
|
||||
layer = bb.utils.get_file_layer(filename, self.tinfoil.config_data, self.get_collection_res())
|
||||
return self.bbfile_collections.get(layer, None)
|
||||
|
||||
def remove_layer_prefix(self, f):
|
||||
"""Remove the layer_dir prefix, e.g., f = /path/to/layer_dir/foo/blah, the
|
||||
return value will be: layer_dir/foo/blah"""
|
||||
f_layerdir = self.get_file_layerdir(f)
|
||||
if not f_layerdir:
|
||||
return f
|
||||
prefix = os.path.join(os.path.dirname(f_layerdir), '')
|
||||
return f[len(prefix):] if f.startswith(prefix) else f
|
||||
|
||||
def do_show_appends(self, args):
|
||||
"""list bbappend files and recipe files they apply to
|
||||
|
||||
Lists recipes with the bbappends that apply to them as subitems.
|
||||
"""
|
||||
if args.pnspec:
|
||||
logger.plain('=== Matched appended recipes ===')
|
||||
else:
|
||||
logger.plain('=== Appended recipes ===')
|
||||
|
||||
|
||||
cooker_data = self.tinfoil.cooker.recipecaches[args.mc]
|
||||
|
||||
pnlist = list(cooker_data.pkg_pn.keys())
|
||||
pnlist.sort()
|
||||
appends = False
|
||||
for pn in pnlist:
|
||||
if args.pnspec:
|
||||
found=False
|
||||
for pnm in args.pnspec:
|
||||
if fnmatch.fnmatch(pn, pnm):
|
||||
found=True
|
||||
break
|
||||
if not found:
|
||||
continue
|
||||
|
||||
if self.show_appends_for_pn(pn, cooker_data, args.mc):
|
||||
appends = True
|
||||
|
||||
if not args.pnspec and self.show_appends_for_skipped(args.mc):
|
||||
appends = True
|
||||
|
||||
if not appends:
|
||||
logger.plain('No append files found')
|
||||
|
||||
def show_appends_for_pn(self, pn, cooker_data, mc):
|
||||
filenames = cooker_data.pkg_pn[pn]
|
||||
if mc:
|
||||
pn = "mc:%s:%s" % (mc, pn)
|
||||
|
||||
best = self.tinfoil.find_best_provider(pn)
|
||||
best_filename = os.path.basename(best[3])
|
||||
|
||||
return self.show_appends_output(filenames, best_filename)
|
||||
|
||||
def show_appends_for_skipped(self, mc):
|
||||
filenames = [os.path.basename(f)
|
||||
for f in self.tinfoil.cooker.skiplist_by_mc[mc].keys()]
|
||||
return self.show_appends_output(filenames, None, " (skipped)")
|
||||
|
||||
def show_appends_output(self, filenames, best_filename, name_suffix = ''):
|
||||
appended, missing = self.get_appends_for_files(filenames)
|
||||
if appended:
|
||||
for basename, appends in appended:
|
||||
logger.plain('%s%s:', basename, name_suffix)
|
||||
for append in appends:
|
||||
logger.plain(' %s', append)
|
||||
|
||||
if best_filename:
|
||||
if best_filename in missing:
|
||||
logger.warning('%s: missing append for preferred version',
|
||||
best_filename)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def get_appends_for_files(self, filenames):
|
||||
appended, notappended = [], []
|
||||
for filename in filenames:
|
||||
_, cls, mc = bb.cache.virtualfn2realfn(filename)
|
||||
if cls:
|
||||
continue
|
||||
|
||||
basename = os.path.basename(filename)
|
||||
appends = self.tinfoil.cooker.collections[mc].get_file_appends(basename)
|
||||
if appends:
|
||||
appended.append((basename, list(appends)))
|
||||
else:
|
||||
notappended.append(basename)
|
||||
return appended, notappended
|
||||
|
||||
def do_show_cross_depends(self, args):
|
||||
"""Show dependencies between recipes that cross layer boundaries.
|
||||
|
||||
Figure out the dependencies between recipes that cross layer boundaries.
|
||||
|
||||
NOTE: .bbappend files can impact the dependencies.
|
||||
"""
|
||||
ignore_layers = (args.ignore or '').split(',')
|
||||
|
||||
pkg_fn = self.tinfoil.cooker_data.pkg_fn
|
||||
bbpath = str(self.tinfoil.config_data.getVar('BBPATH'))
|
||||
self.require_re = re.compile(r"require\s+(.+)")
|
||||
self.include_re = re.compile(r"include\s+(.+)")
|
||||
self.inherit_re = re.compile(r"inherit\s+(.+)")
|
||||
|
||||
global_inherit = (self.tinfoil.config_data.getVar('INHERIT') or "").split()
|
||||
|
||||
# The bb's DEPENDS and RDEPENDS
|
||||
for f in pkg_fn:
|
||||
f = bb.cache.virtualfn2realfn(f)[0]
|
||||
# Get the layername that the file is in
|
||||
layername = self.get_file_layer(f)
|
||||
|
||||
# The DEPENDS
|
||||
deps = self.tinfoil.cooker_data.deps[f]
|
||||
for pn in deps:
|
||||
if pn in self.tinfoil.cooker_data.pkg_pn:
|
||||
best = self.tinfoil.find_best_provider(pn)
|
||||
self.check_cross_depends("DEPENDS", layername, f, best[3], args.filenames, ignore_layers)
|
||||
|
||||
# The RDPENDS
|
||||
all_rdeps = self.tinfoil.cooker_data.rundeps[f].values()
|
||||
# Remove the duplicated or null one.
|
||||
sorted_rdeps = {}
|
||||
# The all_rdeps is the list in list, so we need two for loops
|
||||
for k1 in all_rdeps:
|
||||
for k2 in k1:
|
||||
sorted_rdeps[k2] = 1
|
||||
all_rdeps = sorted_rdeps.keys()
|
||||
for rdep in all_rdeps:
|
||||
all_p, best = self.tinfoil.get_runtime_providers(rdep)
|
||||
if all_p:
|
||||
if f in all_p:
|
||||
# The recipe provides this one itself, ignore
|
||||
continue
|
||||
self.check_cross_depends("RDEPENDS", layername, f, best, args.filenames, ignore_layers)
|
||||
|
||||
# The RRECOMMENDS
|
||||
all_rrecs = self.tinfoil.cooker_data.runrecs[f].values()
|
||||
# Remove the duplicated or null one.
|
||||
sorted_rrecs = {}
|
||||
# The all_rrecs is the list in list, so we need two for loops
|
||||
for k1 in all_rrecs:
|
||||
for k2 in k1:
|
||||
sorted_rrecs[k2] = 1
|
||||
all_rrecs = sorted_rrecs.keys()
|
||||
for rrec in all_rrecs:
|
||||
all_p, best = self.tinfoil.get_runtime_providers(rrec)
|
||||
if all_p:
|
||||
if f in all_p:
|
||||
# The recipe provides this one itself, ignore
|
||||
continue
|
||||
self.check_cross_depends("RRECOMMENDS", layername, f, best, args.filenames, ignore_layers)
|
||||
|
||||
# The inherit class
|
||||
cls_re = re.compile('classes.*/')
|
||||
if f in self.tinfoil.cooker_data.inherits:
|
||||
inherits = self.tinfoil.cooker_data.inherits[f]
|
||||
for cls in inherits:
|
||||
# The inherits' format is [classes/cls, /path/to/classes/cls]
|
||||
# ignore the classes/cls.
|
||||
if not cls_re.match(cls):
|
||||
classname = os.path.splitext(os.path.basename(cls))[0]
|
||||
if classname in global_inherit:
|
||||
continue
|
||||
inherit_layername = self.get_file_layer(cls)
|
||||
if inherit_layername != layername and not inherit_layername in ignore_layers:
|
||||
if not args.filenames:
|
||||
f_short = self.remove_layer_prefix(f)
|
||||
cls = self.remove_layer_prefix(cls)
|
||||
else:
|
||||
f_short = f
|
||||
logger.plain("%s inherits %s" % (f_short, cls))
|
||||
|
||||
# The 'require/include xxx' in the bb file
|
||||
pv_re = re.compile(r"\${PV}")
|
||||
with open(f, 'r') as fnfile:
|
||||
line = fnfile.readline()
|
||||
while line:
|
||||
m, keyword = self.match_require_include(line)
|
||||
# Found the 'require/include xxxx'
|
||||
if m:
|
||||
needed_file = m.group(1)
|
||||
# Replace the ${PV} with the real PV
|
||||
if pv_re.search(needed_file) and f in self.tinfoil.cooker_data.pkg_pepvpr:
|
||||
pv = self.tinfoil.cooker_data.pkg_pepvpr[f][1]
|
||||
needed_file = re.sub(r"\${PV}", pv, needed_file)
|
||||
self.print_cross_files(bbpath, keyword, layername, f, needed_file, args.filenames, ignore_layers)
|
||||
line = fnfile.readline()
|
||||
|
||||
# The "require/include xxx" in conf/machine/*.conf, .inc and .bbclass
|
||||
conf_re = re.compile(r".*/conf/machine/[^\/]*\.conf$")
|
||||
inc_re = re.compile(r".*\.inc$")
|
||||
# The "inherit xxx" in .bbclass
|
||||
bbclass_re = re.compile(r".*\.bbclass$")
|
||||
for layerdir in self.bblayers:
|
||||
layername = self.get_layer_name(layerdir)
|
||||
for dirpath, dirnames, filenames in os.walk(layerdir):
|
||||
for name in filenames:
|
||||
f = os.path.join(dirpath, name)
|
||||
s = conf_re.match(f) or inc_re.match(f) or bbclass_re.match(f)
|
||||
if s:
|
||||
with open(f, 'r') as ffile:
|
||||
line = ffile.readline()
|
||||
while line:
|
||||
m, keyword = self.match_require_include(line)
|
||||
# Only bbclass has the "inherit xxx" here.
|
||||
bbclass=""
|
||||
if not m and f.endswith(".bbclass"):
|
||||
m, keyword = self.match_inherit(line)
|
||||
bbclass=".bbclass"
|
||||
# Find a 'require/include xxxx'
|
||||
if m:
|
||||
self.print_cross_files(bbpath, keyword, layername, f, m.group(1) + bbclass, args.filenames, ignore_layers)
|
||||
line = ffile.readline()
|
||||
|
||||
def print_cross_files(self, bbpath, keyword, layername, f, needed_filename, show_filenames, ignore_layers):
|
||||
"""Print the depends that crosses a layer boundary"""
|
||||
needed_file = bb.utils.which(bbpath, needed_filename)
|
||||
if needed_file:
|
||||
# Which layer is this file from
|
||||
needed_layername = self.get_file_layer(needed_file)
|
||||
if needed_layername != layername and not needed_layername in ignore_layers:
|
||||
if not show_filenames:
|
||||
f = self.remove_layer_prefix(f)
|
||||
needed_file = self.remove_layer_prefix(needed_file)
|
||||
logger.plain("%s %s %s" %(f, keyword, needed_file))
|
||||
|
||||
def match_inherit(self, line):
|
||||
"""Match the inherit xxx line"""
|
||||
return (self.inherit_re.match(line), "inherits")
|
||||
|
||||
def match_require_include(self, line):
|
||||
"""Match the require/include xxx line"""
|
||||
m = self.require_re.match(line)
|
||||
keyword = "requires"
|
||||
if not m:
|
||||
m = self.include_re.match(line)
|
||||
keyword = "includes"
|
||||
return (m, keyword)
|
||||
|
||||
def check_cross_depends(self, keyword, layername, f, needed_file, show_filenames, ignore_layers):
|
||||
"""Print the DEPENDS/RDEPENDS file that crosses a layer boundary"""
|
||||
best_realfn = bb.cache.virtualfn2realfn(needed_file)[0]
|
||||
needed_layername = self.get_file_layer(best_realfn)
|
||||
if needed_layername != layername and not needed_layername in ignore_layers:
|
||||
if not show_filenames:
|
||||
f = self.remove_layer_prefix(f)
|
||||
best_realfn = self.remove_layer_prefix(best_realfn)
|
||||
|
||||
logger.plain("%s %s %s" % (f, keyword, best_realfn))
|
||||
|
||||
def register_commands(self, sp):
|
||||
self.add_command(sp, 'show-layers', self.do_show_layers, parserecipes=False)
|
||||
|
||||
parser_show_overlayed = self.add_command(sp, 'show-overlayed', self.do_show_overlayed)
|
||||
parser_show_overlayed.add_argument('-f', '--filenames', help='instead of the default formatting, list filenames of higher priority recipes with the ones they overlay indented underneath', action='store_true')
|
||||
parser_show_overlayed.add_argument('-s', '--same-version', help='only list overlayed recipes where the version is the same', action='store_true')
|
||||
parser_show_overlayed.add_argument('--mc', help='use specified multiconfig', default='')
|
||||
|
||||
parser_show_recipes = self.add_command(sp, 'show-recipes', self.do_show_recipes)
|
||||
parser_show_recipes.add_argument('-f', '--filenames', help='instead of the default formatting, list filenames of higher priority recipes with the ones they overlay indented underneath', action='store_true')
|
||||
parser_show_recipes.add_argument('-r', '--recipes-only', help='instead of the default formatting, list recipes only', action='store_true')
|
||||
parser_show_recipes.add_argument('-m', '--multiple', help='only list where multiple recipes (in the same layer or different layers) exist for the same recipe name', action='store_true')
|
||||
parser_show_recipes.add_argument('-i', '--inherits', help='only list recipes that inherit the named class(es) - separate multiple classes using , (without spaces)', metavar='CLASS', default='')
|
||||
parser_show_recipes.add_argument('-l', '--layer', help='only list recipes from the selected layer', default='')
|
||||
parser_show_recipes.add_argument('-b', '--bare', help='output just names without the "(skipped)" marker', action='store_true')
|
||||
parser_show_recipes.add_argument('--mc', help='use specified multiconfig', default='')
|
||||
parser_show_recipes.add_argument('pnspec', nargs='*', help='optional recipe name specification (wildcards allowed, enclose in quotes to avoid shell expansion)')
|
||||
|
||||
parser_show_appends = self.add_command(sp, 'show-appends', self.do_show_appends)
|
||||
parser_show_appends.add_argument('pnspec', nargs='*', help='optional recipe name specification (wildcards allowed, enclose in quotes to avoid shell expansion)')
|
||||
parser_show_appends.add_argument('--mc', help='use specified multiconfig', default='')
|
||||
|
||||
parser_show_cross_depends = self.add_command(sp, 'show-cross-depends', self.do_show_cross_depends)
|
||||
parser_show_cross_depends.add_argument('-f', '--filenames', help='show full file path', action='store_true')
|
||||
parser_show_cross_depends.add_argument('-i', '--ignore', help='ignore dependencies on items in the specified layer(s) (split multiple layer names with commas, no spaces)', metavar='LAYERNAME')
|
||||
Reference in New Issue
Block a user