#!/usr/bin/env python3 # Copyright (C) 2023 Hirschmann Automation and Control GmbH # # - list all recipes that are supported by the CoreOS team import sys import optparse import os import re scripts_path = os.path.abspath(os.path.dirname(os.path.abspath(sys.argv[0]))) # Add the path if we have own libs lib_path = os.path.abspath(scripts_path + '/../lib') sys.path = sys.path + [lib_path] # Add the OE lib path lib_path = os.path.abspath(scripts_path + '/../external-layers/openembedded-core/scripts/lib') sys.path = sys.path + [lib_path] import scriptpath # For importing the following modules bitbakepath = scriptpath.add_bitbake_lib_path() if not bitbakepath: sys.stderr.write("Unable to find bitbake by searching parent directory of this script or PATH\n") sys.exit(1) import bb.cooker import bb.providers import bb.tinfoil from pprint import pprint def get_fnlist(bbhandler, pkg_pn): ''' Get all recipe file names ''' (latest_versions, preferred_versions, required_versions) = bb.providers.findProviders(bbhandler.config_data, bbhandler.cooker.recipecaches[''], pkg_pn) fn_list = [] for pn in sorted(pkg_pn): # use the preferred version fn_list.append(preferred_versions[pn][1]) return fn_list def get_recipesdata(bbhandler): ''' Get data of all available recipes ''' pkg_pn = bbhandler.cooker.recipecaches[''].pkg_pn pkg_dict = {} supported_pkg_dict = {} fn_list = get_fnlist(bbhandler, pkg_pn) size = str(len(fn_list)) i = 0 for fn in fn_list: print(size + "/" + str(i)) i += 1 data = bbhandler.parse_recipe_file(fn) maintainer = data.getVar("COREOS_RECIPE_MAINTAINER") pn = data.getVar("PN") packages = data.getVar("PACKAGES") packages += data.getVar("PROVIDES") pkg_dict[pn] = data if maintainer: supported_pkg_dict[pn] = data for pkg in packages.split(): pkg_dict[pkg] = data if maintainer: supported_pkg_dict[pkg] = data return pkg_dict, supported_pkg_dict def resolve_dependencies(pkg_dict, supported_pkg_dict): ''' Resolve dependencies and add them to supported packages ''' sup_with_dep_dict = {} for pkg in supported_pkg_dict: depends = supported_pkg_dict[pkg].getVar("DEPENDS") or '' rdepends = supported_pkg_dict[pkg].getVar("RDEPENDS") or '' sup_with_dep_dict[pkg] = pkg_dict[pkg] for d_pkg in depends.split(): if ("virtual/" in d_pkg) or ("native" in d_pkg): continue sup_with_dep_dict[d_pkg] = pkg_dict[d_pkg] for r_pkg in rdepends.split(): if ("virtual/" in r_pkg) or ("native" in r_pkg): continue sup_with_dep_dict[r_pkg] = pkg_dict[r_pkg] return sup_with_dep_dict def display(supported_pkg_dict): ''' Display all pkgs and COREOS_RECIPE_MAINTAINER information ''' print(f'{str("RECIPE NAMES:"):40} {str("META-LAYER:"):40} {str("COS-MAINTAINER:"):50}') for pn in supported_pkg_dict: recipe_name = supported_pkg_dict[pn].getVar("P") recipe_path = supported_pkg_dict[pn].getVar("FILE") meta_layer = re.search("(?<=/layers/)(.*)(?=/recipe)", recipe_path).group(0) maintainer = supported_pkg_dict[pn].getVar("COREOS_RECIPE_MAINTAINER") or 'Supported by Dependency' print(f'{recipe_name:40} {meta_layer:40} {maintainer:50}') def get_unique_list(supported_pkg_dict): ''' Create a list that only contains one package based on PN ''' unique_dict = {} for pkg in supported_pkg_dict: pn = supported_pkg_dict[pkg].getVar("P") unique_dict[pn] = supported_pkg_dict[pkg] return unique_dict def print_to_file(supported_pkg_dict, file): ''' print list to a file ''' with open(file, "w") as file: file.write(f'{str("RECIPE NAMES:"):40} {str("META-LAYER:"):40} {str("COS-MAINTAINER:"):50}\n') for pn in supported_pkg_dict: recipe_name = supported_pkg_dict[pn].getVar("P") recipe_path = supported_pkg_dict[pn].getVar("FILE") meta_layer = re.search("(?<=/layers/)(.*)(?=/recipe)", recipe_path).group(0) maintainer = supported_pkg_dict[pn].getVar("COREOS_RECIPE_MAINTAINER") or 'Supported by Dependency' file.write(f'{recipe_name:40} {meta_layer:40} {maintainer:50}\n') def main(): parser = optparse.OptionParser( description = "Lists all recipes supported by CoreOS.", usage = """ %prog [options]""") parser.add_option("-p", "--print", help = "print all recipes that are supported", action="store_const", dest="print", default=True) parser.add_option("-f", "--file", help = "store in file", action="store", dest="file", type="string") options, args = parser.parse_args(sys.argv) with bb.tinfoil.Tinfoil() as bbhandler: bbhandler.prepare() print("Gathering recipe data...") pkg_dict, supported_pkg_dict = get_recipesdata(bbhandler) new_len = len(supported_pkg_dict) old_len = 0 while old_len != new_len: supported_pkg_dict = resolve_dependencies(pkg_dict, supported_pkg_dict) old_len = new_len new_len = len(supported_pkg_dict) unique_dict = get_unique_list(supported_pkg_dict) supported_pkg_dict = unique_dict if options.print: display(supported_pkg_dict) if options.file: print_to_file(supported_pkg_dict, options.file) if __name__ == "__main__": main()