From 972dcfcdbfe75dcfeb777150c136576cf1a71e99 Mon Sep 17 00:00:00 2001 From: Tudor Florea Date: Fri, 9 Oct 2015 22:59:03 +0200 Subject: initial commit for Enea Linux 5.0 arm Signed-off-by: Tudor Florea --- scripts/lib/bsp/kernel.py | 1071 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1071 insertions(+) create mode 100644 scripts/lib/bsp/kernel.py (limited to 'scripts/lib/bsp/kernel.py') diff --git a/scripts/lib/bsp/kernel.py b/scripts/lib/bsp/kernel.py new file mode 100644 index 0000000000..ba68b60fcb --- /dev/null +++ b/scripts/lib/bsp/kernel.py @@ -0,0 +1,1071 @@ +# ex:ts=4:sw=4:sts=4:et +# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- +# +# Copyright (c) 2012, Intel Corporation. +# All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# DESCRIPTION +# This module implements the kernel-related functions used by +# 'yocto-kernel' to manage kernel config items and patches for Yocto +# BSPs. +# +# AUTHORS +# Tom Zanussi +# + +import sys +import os +import shutil +from tags import * +import glob +import subprocess +from engine import create_context + + +def find_bblayers(): + """ + Find and return a sanitized list of the layers found in BBLAYERS. + """ + try: + builddir = os.environ["BUILDDIR"] + except KeyError: + print "BUILDDIR not found, exiting. (Did you forget to source oe-init-build-env?)" + sys.exit(1) + bblayers_conf = os.path.join(builddir, "conf/bblayers.conf") + + layers = [] + + bitbake_env_cmd = "bitbake -e" + bitbake_env_lines = subprocess.Popen(bitbake_env_cmd, shell=True, + stdout=subprocess.PIPE).stdout.read() + + if not bitbake_env_lines: + print "Couldn't get '%s' output, exiting." % bitbake_env_cmd + sys.exit(1) + + for line in bitbake_env_lines.split('\n'): + bblayers = get_line_val(line, "BBLAYERS") + if (bblayers): + break + + if not bblayers: + print "Couldn't find BBLAYERS in %s output, exiting." % \ + bitbake_env_cmd + sys.exit(1) + + raw_layers = bblayers.split() + + for layer in raw_layers: + if layer == 'BBLAYERS' or '=' in layer: + continue + layers.append(layer) + + return layers + + +def get_line_val(line, key): + """ + Extract the value from the VAR="val" string + """ + if line.startswith(key + "="): + stripped_line = line.split('=')[1] + stripped_line = stripped_line.replace('\"', '') + return stripped_line + return None + + +def find_meta_layer(): + """ + Find and return the meta layer in BBLAYERS. + """ + layers = find_bblayers() + + for layer in layers: + if layer.endswith("meta"): + return layer + + return None + + +def find_bsp_layer(machine): + """ + Find and return a machine's BSP layer in BBLAYERS. + """ + layers = find_bblayers() + + for layer in layers: + if layer.endswith(machine): + return layer + + print "Unable to find the BSP layer for machine %s." % machine + print "Please make sure it is listed in bblayers.conf" + sys.exit(1) + + +def gen_choices_str(choices): + """ + Generate a numbered list of choices from a list of choices for + display to the user. + """ + choices_str = "" + + for i, choice in enumerate(choices): + choices_str += "\t" + str(i + 1) + ") " + choice + "\n" + + return choices_str + + +def open_user_file(scripts_path, machine, userfile, mode): + """ + Find one of the user files (user-config.cfg, user-patches.scc) + associated with the machine (could be in files/, + linux-yocto-custom/, etc). Returns the open file if found, None + otherwise. + + The caller is responsible for closing the file returned. + """ + layer = find_bsp_layer(machine) + linuxdir = os.path.join(layer, "recipes-kernel/linux") + linuxdir_list = os.listdir(linuxdir) + for fileobj in linuxdir_list: + fileobj_path = os.path.join(linuxdir, fileobj) + if os.path.isdir(fileobj_path): + userfile_name = os.path.join(fileobj_path, userfile) + try: + f = open(userfile_name, mode) + return f + except IOError: + continue + return None + + +def read_config_items(scripts_path, machine): + """ + Find and return a list of config items (CONFIG_XXX) in a machine's + user-defined config fragment [${machine}-user-config.cfg]. + """ + config_items = [] + + f = open_user_file(scripts_path, machine, machine+"-user-config.cfg", "r") + lines = f.readlines() + for line in lines: + s = line.strip() + if s and not s.startswith("#"): + config_items.append(s) + f.close() + + return config_items + + +def write_config_items(scripts_path, machine, config_items): + """ + Write (replace) the list of config items (CONFIG_XXX) in a + machine's user-defined config fragment [${machine}=user-config.cfg]. + """ + f = open_user_file(scripts_path, machine, machine+"-user-config.cfg", "w") + for item in config_items: + f.write(item + "\n") + f.close() + + kernel_contents_changed(scripts_path, machine) + + +def yocto_kernel_config_list(scripts_path, machine): + """ + Display the list of config items (CONFIG_XXX) in a machine's + user-defined config fragment [${machine}-user-config.cfg]. + """ + config_items = read_config_items(scripts_path, machine) + + print "The current set of machine-specific kernel config items for %s is:" % machine + print gen_choices_str(config_items) + + +def yocto_kernel_config_rm(scripts_path, machine): + """ + Display the list of config items (CONFIG_XXX) in a machine's + user-defined config fragment [${machine}-user-config.cfg], prompt the user + for one or more to remove, and remove them. + """ + config_items = read_config_items(scripts_path, machine) + + print "Specify the kernel config items to remove:" + input = raw_input(gen_choices_str(config_items)) + rm_choices = input.split() + rm_choices.sort() + + removed = [] + + for choice in reversed(rm_choices): + try: + idx = int(choice) - 1 + except ValueError: + print "Invalid choice (%s), exiting" % choice + sys.exit(1) + if idx < 0 or idx >= len(config_items): + print "Invalid choice (%d), exiting" % (idx + 1) + sys.exit(1) + removed.append(config_items.pop(idx)) + + write_config_items(scripts_path, machine, config_items) + + print "Removed items:" + for r in removed: + print "\t%s" % r + + +def yocto_kernel_config_add(scripts_path, machine, config_items): + """ + Add one or more config items (CONFIG_XXX) to a machine's + user-defined config fragment [${machine}-user-config.cfg]. + """ + new_items = [] + dup_items = [] + + cur_items = read_config_items(scripts_path, machine) + + for item in config_items: + if not item.startswith("CONFIG") or (not "=y" in item and not "=m" in item): + print "Invalid config item (%s), exiting" % item + sys.exit(1) + if item not in cur_items and item not in new_items: + new_items.append(item) + else: + dup_items.append(item) + + if len(new_items) > 0: + cur_items.extend(new_items) + write_config_items(scripts_path, machine, cur_items) + print "Added item%s:" % ("" if len(new_items)==1 else "s") + for n in new_items: + print "\t%s" % n + + if len(dup_items) > 0: + output="The following item%s already exist%s in the current configuration, ignoring %s:" % \ + (("","s", "it") if len(dup_items)==1 else ("s", "", "them" )) + print output + for n in dup_items: + print "\t%s" % n + +def find_current_kernel(bsp_layer, machine): + """ + Determine the kernel and version currently being used in the BSP. + """ + machine_conf = os.path.join(bsp_layer, "conf/machine/" + machine + ".conf") + + preferred_kernel = preferred_kernel_version = preferred_version_varname = None + + f = open(machine_conf, "r") + lines = f.readlines() + for line in lines: + if line.strip().startswith("PREFERRED_PROVIDER_virtual/kernel"): + preferred_kernel = line.split()[-1] + preferred_kernel = preferred_kernel.replace('\"','') + preferred_version_varname = "PREFERRED_VERSION_" + preferred_kernel + if preferred_version_varname and line.strip().startswith(preferred_version_varname): + preferred_kernel_version = line.split()[-1] + preferred_kernel_version = preferred_kernel_version.replace('\"','') + preferred_kernel_version = preferred_kernel_version.replace('%','') + + if preferred_kernel and preferred_kernel_version: + return preferred_kernel + "_" + preferred_kernel_version + elif preferred_kernel: + return preferred_kernel + + +def find_filesdir(scripts_path, machine): + """ + Find the name of the 'files' dir associated with the machine + (could be in files/, linux-yocto-custom/, etc). Returns the name + of the files dir if found, None otherwise. + """ + layer = find_bsp_layer(machine) + filesdir = None + linuxdir = os.path.join(layer, "recipes-kernel/linux") + linuxdir_list = os.listdir(linuxdir) + for fileobj in linuxdir_list: + fileobj_path = os.path.join(linuxdir, fileobj) + if os.path.isdir(fileobj_path): + # this could be files/ or linux-yocto-custom/, we have no way of distinguishing + # so we take the first (and normally only) dir we find as the 'filesdir' + filesdir = fileobj_path + + return filesdir + + +def read_patch_items(scripts_path, machine): + """ + Find and return a list of patch items in a machine's user-defined + patch list [${machine}-user-patches.scc]. + """ + patch_items = [] + + f = open_user_file(scripts_path, machine, machine+"-user-patches.scc", "r") + lines = f.readlines() + for line in lines: + s = line.strip() + if s and not s.startswith("#"): + fields = s.split() + if not fields[0] == "patch": + continue + patch_items.append(fields[1]) + f.close() + + return patch_items + + +def write_patch_items(scripts_path, machine, patch_items): + """ + Write (replace) the list of patches in a machine's user-defined + patch list [${machine}-user-patches.scc]. + """ + f = open_user_file(scripts_path, machine, machine+"-user-patches.scc", "w") + for item in patch_items: + f.write("patch " + item + "\n") + f.close() + + kernel_contents_changed(scripts_path, machine) + + +def yocto_kernel_patch_list(scripts_path, machine): + """ + Display the list of patches in a machine's user-defined patch list + [${machine}-user-patches.scc]. + """ + patches = read_patch_items(scripts_path, machine) + + print "The current set of machine-specific patches for %s is:" % machine + print gen_choices_str(patches) + + +def yocto_kernel_patch_rm(scripts_path, machine): + """ + Remove one or more patches from a machine's user-defined patch + list [${machine}-user-patches.scc]. + """ + patches = read_patch_items(scripts_path, machine) + + print "Specify the patches to remove:" + input = raw_input(gen_choices_str(patches)) + rm_choices = input.split() + rm_choices.sort() + + removed = [] + + filesdir = find_filesdir(scripts_path, machine) + if not filesdir: + print "Couldn't rm patch(es) since we couldn't find a 'files' dir" + sys.exit(1) + + for choice in reversed(rm_choices): + try: + idx = int(choice) - 1 + except ValueError: + print "Invalid choice (%s), exiting" % choice + sys.exit(1) + if idx < 0 or idx >= len(patches): + print "Invalid choice (%d), exiting" % (idx + 1) + sys.exit(1) + filesdir_patch = os.path.join(filesdir, patches[idx]) + if os.path.isfile(filesdir_patch): + os.remove(filesdir_patch) + removed.append(patches[idx]) + patches.pop(idx) + + write_patch_items(scripts_path, machine, patches) + + print "Removed patches:" + for r in removed: + print "\t%s" % r + + +def yocto_kernel_patch_add(scripts_path, machine, patches): + """ + Add one or more patches to a machine's user-defined patch list + [${machine}-user-patches.scc]. + """ + existing_patches = read_patch_items(scripts_path, machine) + + for patch in patches: + if os.path.basename(patch) in existing_patches: + print "Couldn't add patch (%s) since it's already been added" % os.path.basename(patch) + sys.exit(1) + + filesdir = find_filesdir(scripts_path, machine) + if not filesdir: + print "Couldn't add patch (%s) since we couldn't find a 'files' dir to add it to" % os.path.basename(patch) + sys.exit(1) + + new_patches = [] + + for patch in patches: + if not os.path.isfile(patch): + print "Couldn't find patch (%s), exiting" % patch + sys.exit(1) + basename = os.path.basename(patch) + filesdir_patch = os.path.join(filesdir, basename) + shutil.copyfile(patch, filesdir_patch) + new_patches.append(basename) + + cur_items = read_patch_items(scripts_path, machine) + cur_items.extend(new_patches) + write_patch_items(scripts_path, machine, cur_items) + + print "Added patches:" + for n in new_patches: + print "\t%s" % n + + +def inc_pr(line): + """ + Add 1 to the PR value in the given bbappend PR line. For the PR + lines in kernel .bbappends after modifications. Handles PRs of + the form PR := "${PR}.1" as well as PR = "r0". + """ + idx = line.find("\"") + + pr_str = line[idx:] + pr_str = pr_str.replace('\"','') + fields = pr_str.split('.') + if len(fields) > 1: + fields[1] = str(int(fields[1]) + 1) + pr_str = "\"" + '.'.join(fields) + "\"\n" + else: + pr_val = pr_str[1:] + pr_str = "\"" + "r" + str(int(pr_val) + 1) + "\"\n" + idx2 = line.find("\"", idx + 1) + line = line[:idx] + pr_str + + return line + + +def kernel_contents_changed(scripts_path, machine): + """ + Do what we need to do to notify the system that the kernel + recipe's contents have changed. + """ + layer = find_bsp_layer(machine) + + kernel = find_current_kernel(layer, machine) + if not kernel: + print "Couldn't determine the kernel for this BSP, exiting." + sys.exit(1) + + kernel_bbfile = os.path.join(layer, "recipes-kernel/linux/" + kernel + ".bbappend") + if not os.path.isfile(kernel_bbfile): + kernel_bbfile = os.path.join(layer, "recipes-kernel/linux/" + kernel + ".bb") + if not os.path.isfile(kernel_bbfile): + return + kernel_bbfile_prev = kernel_bbfile + ".prev" + shutil.copyfile(kernel_bbfile, kernel_bbfile_prev) + + ifile = open(kernel_bbfile_prev, "r") + ofile = open(kernel_bbfile, "w") + ifile_lines = ifile.readlines() + for ifile_line in ifile_lines: + if ifile_line.strip().startswith("PR"): + ifile_line = inc_pr(ifile_line) + ofile.write(ifile_line) + ofile.close() + ifile.close() + + +def kernels(context): + """ + Return the list of available kernels in the BSP i.e. corresponding + to the kernel .bbappends found in the layer. + """ + archdir = os.path.join(context["scripts_path"], "lib/bsp/substrate/target/arch/" + context["arch"]) + kerndir = os.path.join(archdir, "recipes-kernel/linux") + bbglob = os.path.join(kerndir, "*.bbappend") + + bbappends = glob.glob(bbglob) + + kernels = [] + + for kernel in bbappends: + filename = os.path.splitext(os.path.basename(kernel))[0] + idx = filename.find(CLOSE_TAG) + if idx != -1: + filename = filename[idx + len(CLOSE_TAG):].strip() + kernels.append(filename) + + kernels.append("custom") + + return kernels + + +def extract_giturl(file): + """ + Extract the git url of the kernel repo from the kernel recipe's + SRC_URI. + """ + url = None + f = open(file, "r") + lines = f.readlines() + for line in lines: + line = line.strip() + if line.startswith("SRC_URI"): + line = line[len("SRC_URI"):].strip() + if line.startswith("="): + line = line[1:].strip() + if line.startswith("\""): + line = line[1:].strip() + prot = "git" + for s in line.split(";"): + if s.startswith("git://"): + url = s + if s.startswith("protocol="): + prot = s.split("=")[1] + if url: + url = prot + url[3:] + return url + + +def find_giturl(context): + """ + Find the git url of the kernel repo from the kernel recipe's + SRC_URI. + """ + name = context["name"] + filebase = context["filename"] + scripts_path = context["scripts_path"] + + meta_layer = find_meta_layer() + + kerndir = os.path.join(meta_layer, "recipes-kernel/linux") + bbglob = os.path.join(kerndir, "*.bb") + bbs = glob.glob(bbglob) + for kernel in bbs: + filename = os.path.splitext(os.path.basename(kernel))[0] + if filename in filebase: + giturl = extract_giturl(kernel) + return giturl + + return None + + +def read_features(scripts_path, machine): + """ + Find and return a list of features in a machine's user-defined + features fragment [${machine}-user-features.scc]. + """ + features = [] + + f = open_user_file(scripts_path, machine, machine+"-user-features.scc", "r") + lines = f.readlines() + for line in lines: + s = line.strip() + if s and not s.startswith("#"): + feature_include = s.split() + features.append(feature_include[1].strip()) + f.close() + + return features + + +def write_features(scripts_path, machine, features): + """ + Write (replace) the list of feature items in a + machine's user-defined features fragment [${machine}=user-features.cfg]. + """ + f = open_user_file(scripts_path, machine, machine+"-user-features.scc", "w") + for item in features: + f.write("include " + item + "\n") + f.close() + + kernel_contents_changed(scripts_path, machine) + + +def yocto_kernel_feature_list(scripts_path, machine): + """ + Display the list of features used in a machine's user-defined + features fragment [${machine}-user-features.scc]. + """ + features = read_features(scripts_path, machine) + + print "The current set of machine-specific features for %s is:" % machine + print gen_choices_str(features) + + +def yocto_kernel_feature_rm(scripts_path, machine): + """ + Display the list of features used in a machine's user-defined + features fragment [${machine}-user-features.scc], prompt the user + for one or more to remove, and remove them. + """ + features = read_features(scripts_path, machine) + + print "Specify the features to remove:" + input = raw_input(gen_choices_str(features)) + rm_choices = input.split() + rm_choices.sort() + + removed = [] + + for choice in reversed(rm_choices): + try: + idx = int(choice) - 1 + except ValueError: + print "Invalid choice (%s), exiting" % choice + sys.exit(1) + if idx < 0 or idx >= len(features): + print "Invalid choice (%d), exiting" % (idx + 1) + sys.exit(1) + removed.append(features.pop(idx)) + + write_features(scripts_path, machine, features) + + print "Removed features:" + for r in removed: + print "\t%s" % r + + +def yocto_kernel_feature_add(scripts_path, machine, features): + """ + Add one or more features a machine's user-defined features + fragment [${machine}-user-features.scc]. + """ + new_items = [] + + for item in features: + if not item.endswith(".scc"): + print "Invalid feature (%s), exiting" % item + sys.exit(1) + new_items.append(item) + + cur_items = read_features(scripts_path, machine) + cur_items.extend(new_items) + + write_features(scripts_path, machine, cur_items) + + print "Added features:" + for n in new_items: + print "\t%s" % n + + +def find_feature_url(git_url): + """ + Find the url of the kern-features.rc kernel for the kernel repo + specified from the BSP's kernel recipe SRC_URI. + """ + feature_url = "" + if git_url.startswith("git://"): + git_url = git_url[len("git://"):].strip() + s = git_url.split("/") + if s[1].endswith(".git"): + s[1] = s[1][:len(s[1]) - len(".git")] + feature_url = "http://" + s[0] + "/cgit/cgit.cgi/" + s[1] + \ + "/plain/meta/cfg/kern-features.rc?h=meta" + + return feature_url + + +def find_feature_desc(lines): + """ + Find the feature description and compatibility in the passed-in + set of lines. Returns a string string of the form 'desc + [compat]'. + """ + desc = "no description available" + compat = "unknown" + + for line in lines: + idx = line.find("KFEATURE_DESCRIPTION") + if idx != -1: + desc = line[idx + len("KFEATURE_DESCRIPTION"):].strip() + if desc.startswith("\""): + desc = desc[1:] + if desc.endswith("\""): + desc = desc[:-1] + else: + idx = line.find("KFEATURE_COMPATIBILITY") + if idx != -1: + compat = line[idx + len("KFEATURE_COMPATIBILITY"):].strip() + + return desc + " [" + compat + "]" + + +def print_feature_descs(layer, feature_dir): + """ + Print the feature descriptions for the features in feature_dir. + """ + kernel_files_features = os.path.join(layer, "recipes-kernel/linux/files/" + + feature_dir) + for root, dirs, files in os.walk(kernel_files_features): + for file in files: + if file.endswith("~") or file.endswith("#"): + continue + if file.endswith(".scc"): + fullpath = os.path.join(layer, "recipes-kernel/linux/files/" + + feature_dir + "/" + file) + f = open(fullpath) + feature_desc = find_feature_desc(f.readlines()) + print feature_dir + "/" + file + ": " + feature_desc + + +def yocto_kernel_available_features_list(scripts_path, machine): + """ + Display the list of all the kernel features available for use in + BSPs, as gathered from the set of feature sources. + """ + layer = find_bsp_layer(machine) + kernel = find_current_kernel(layer, machine) + if not kernel: + print "Couldn't determine the kernel for this BSP, exiting." + sys.exit(1) + + context = create_context(machine, "arch", scripts_path) + context["name"] = "name" + context["filename"] = kernel + giturl = find_giturl(context) + feature_url = find_feature_url(giturl) + + feature_cmd = "wget -q -O - " + feature_url + tmp = subprocess.Popen(feature_cmd, shell=True, stdout=subprocess.PIPE).stdout.read() + + print "The current set of kernel features available to %s is:\n" % machine + + if tmp: + tmpline = tmp.split("\n") + in_kernel_options = False + for line in tmpline: + if not "=" in line: + if in_kernel_options: + break + if "kernel-options" in line: + in_kernel_options = True + continue + if in_kernel_options: + feature_def = line.split("=") + feature_type = feature_def[0].strip() + feature = feature_def[1].strip() + desc = get_feature_desc(giturl, feature) + print "%s: %s" % (feature, desc) + + print "[local]" + + print_feature_descs(layer, "cfg") + print_feature_descs(layer, "features") + + +def find_feature_desc_url(git_url, feature): + """ + Find the url of the kernel feature in the kernel repo specified + from the BSP's kernel recipe SRC_URI. + """ + feature_desc_url = "" + if git_url.startswith("git://"): + git_url = git_url[len("git://"):].strip() + s = git_url.split("/") + if s[1].endswith(".git"): + s[1] = s[1][:len(s[1]) - len(".git")] + feature_desc_url = "http://" + s[0] + "/cgit/cgit.cgi/" + s[1] + \ + "/plain/meta/cfg/kernel-cache/" + feature + "?h=meta" + + return feature_desc_url + + +def get_feature_desc(git_url, feature): + """ + Return a feature description of the form 'description [compatibility] + BSPs, as gathered from the set of feature sources. + """ + feature_desc_url = find_feature_desc_url(git_url, feature) + feature_desc_cmd = "wget -q -O - " + feature_desc_url + tmp = subprocess.Popen(feature_desc_cmd, shell=True, stdout=subprocess.PIPE).stdout.read() + + return find_feature_desc(tmp.split("\n")) + + +def yocto_kernel_feature_describe(scripts_path, machine, feature): + """ + Display the description of a specific kernel feature available for + use in a BSP. + """ + layer = find_bsp_layer(machine) + + kernel = find_current_kernel(layer, machine) + if not kernel: + print "Couldn't determine the kernel for this BSP, exiting." + sys.exit(1) + + context = create_context(machine, "arch", scripts_path) + context["name"] = "name" + context["filename"] = kernel + giturl = find_giturl(context) + + desc = get_feature_desc(giturl, feature) + + print desc + + +def check_feature_name(feature_name): + """ + Sanity-check the feature name for create/destroy. Return False if not OK. + """ + if not feature_name.endswith(".scc"): + print "Invalid feature name (must end with .scc) [%s], exiting" % feature_name + return False + + if "/" in feature_name: + print "Invalid feature name (don't specify directory) [%s], exiting" % feature_name + return False + + return True + + +def check_create_input(feature_items): + """ + Sanity-check the create input. Return False if not OK. + """ + if not check_feature_name(feature_items[0]): + return False + + if feature_items[1].endswith(".patch") or feature_items[1].startswith("CONFIG_"): + print "Missing description and/or compatibilty [%s], exiting" % feature_items[1] + return False + + if feature_items[2].endswith(".patch") or feature_items[2].startswith("CONFIG_"): + print "Missing description and/or compatibility [%s], exiting" % feature_items[1] + return False + + return True + + +def yocto_kernel_feature_create(scripts_path, machine, feature_items): + """ + Create a recipe-space kernel feature in a BSP. + """ + if not check_create_input(feature_items): + sys.exit(1) + + feature = feature_items[0] + feature_basename = feature.split(".")[0] + feature_description = feature_items[1] + feature_compat = feature_items[2] + + patches = [] + cfg_items = [] + + for item in feature_items[3:]: + if item.endswith(".patch"): + patches.append(item) + elif item.startswith("CONFIG"): + if ("=y" in item or "=m" in item): + cfg_items.append(item) + else: + print "Invalid feature item (must be .patch or CONFIG_*) [%s], exiting" % item + sys.exit(1) + + feature_dirname = "cfg" + if patches: + feature_dirname = "features" + + filesdir = find_filesdir(scripts_path, machine) + if not filesdir: + print "Couldn't add feature (%s), no 'files' dir found" % feature + sys.exit(1) + + featdir = os.path.join(filesdir, feature_dirname) + if not os.path.exists(featdir): + os.mkdir(featdir) + + for patch in patches: + if not os.path.isfile(patch): + print "Couldn't find patch (%s), exiting" % patch + sys.exit(1) + basename = os.path.basename(patch) + featdir_patch = os.path.join(featdir, basename) + shutil.copyfile(patch, featdir_patch) + + new_cfg_filename = os.path.join(featdir, feature_basename + ".cfg") + new_cfg_file = open(new_cfg_filename, "w") + for cfg_item in cfg_items: + new_cfg_file.write(cfg_item + "\n") + new_cfg_file.close() + + new_feature_filename = os.path.join(featdir, feature_basename + ".scc") + new_feature_file = open(new_feature_filename, "w") + new_feature_file.write("define KFEATURE_DESCRIPTION \"" + feature_description + "\"\n") + new_feature_file.write("define KFEATURE_COMPATIBILITY " + feature_compat + "\n\n") + + for patch in patches: + patch_dir, patch_file = os.path.split(patch) + new_feature_file.write("patch " + patch_file + "\n") + + new_feature_file.write("kconf non-hardware " + feature_basename + ".cfg\n") + new_feature_file.close() + + print "Added feature:" + print "\t%s" % feature_dirname + "/" + feature + + +def feature_in_use(scripts_path, machine, feature): + """ + Determine whether the specified feature is in use by the BSP. + Return True if so, False otherwise. + """ + features = read_features(scripts_path, machine) + for f in features: + if f == feature: + return True + return False + + +def feature_remove(scripts_path, machine, feature): + """ + Remove the specified feature from the available recipe-space + features defined for the BSP. + """ + features = read_features(scripts_path, machine) + new_features = [] + for f in features: + if f == feature: + continue + new_features.append(f) + write_features(scripts_path, machine, new_features) + + +def yocto_kernel_feature_destroy(scripts_path, machine, feature): + """ + Remove a recipe-space kernel feature from a BSP. + """ + if not check_feature_name(feature): + sys.exit(1) + + if feature_in_use(scripts_path, machine, "features/" + feature) or \ + feature_in_use(scripts_path, machine, "cfg/" + feature): + print "Feature %s is in use (use 'feature rm' to un-use it first), exiting" % feature + sys.exit(1) + + filesdir = find_filesdir(scripts_path, machine) + if not filesdir: + print "Couldn't destroy feature (%s), no 'files' dir found" % feature + sys.exit(1) + + feature_dirname = "features" + featdir = os.path.join(filesdir, feature_dirname) + if not os.path.exists(featdir): + print "Couldn't find feature directory (%s)" % feature_dirname + sys.exit(1) + + feature_fqn = os.path.join(featdir, feature) + if not os.path.exists(feature_fqn): + feature_dirname = "cfg" + featdir = os.path.join(filesdir, feature_dirname) + if not os.path.exists(featdir): + print "Couldn't find feature directory (%s)" % feature_dirname + sys.exit(1) + feature_fqn = os.path.join(featdir, feature_filename) + if not os.path.exists(feature_fqn): + print "Couldn't find feature (%s)" % feature + sys.exit(1) + + f = open(feature_fqn, "r") + lines = f.readlines() + for line in lines: + s = line.strip() + if s.startswith("patch ") or s.startswith("kconf "): + split_line = s.split() + filename = os.path.join(featdir, split_line[-1]) + if os.path.exists(filename): + os.remove(filename) + f.close() + os.remove(feature_fqn) + + feature_remove(scripts_path, machine, feature) + + print "Removed feature:" + print "\t%s" % feature_dirname + "/" + feature + + +def base_branches(context): + """ + Return a list of the base branches found in the kernel git repo. + """ + giturl = find_giturl(context) + + print "Getting branches from remote repo %s..." % giturl + + gitcmd = "git ls-remote %s *heads* 2>&1" % (giturl) + tmp = subprocess.Popen(gitcmd, shell=True, stdout=subprocess.PIPE).stdout.read() + + branches = [] + + if tmp: + tmpline = tmp.split("\n") + for line in tmpline: + if len(line)==0: + break; + if not line.endswith("base"): + continue; + idx = line.find("refs/heads/") + kbranch = line[idx + len("refs/heads/"):] + if kbranch.find("/") == -1 and kbranch.find("base") == -1: + continue + idx = kbranch.find("base") + branches.append(kbranch[:idx - 1]) + + return branches + + +def all_branches(context): + """ + Return a list of all the branches found in the kernel git repo. + """ + giturl = find_giturl(context) + + print "Getting branches from remote repo %s..." % giturl + + gitcmd = "git ls-remote %s *heads* 2>&1" % (giturl) + tmp = subprocess.Popen(gitcmd, shell=True, stdout=subprocess.PIPE).stdout.read() + + branches = [] + + base_prefixes = None + + try: + branches_base = context["branches_base"] + if branches_base: + base_prefixes = branches_base.split(":") + except KeyError: + pass + + arch = context["arch"] + + if tmp: + tmpline = tmp.split("\n") + for line in tmpline: + if len(line)==0: + break; + idx = line.find("refs/heads/") + kbranch = line[idx + len("refs/heads/"):] + kbranch_prefix = kbranch.rsplit("/", 1)[0] + + if base_prefixes: + for base_prefix in base_prefixes: + if kbranch_prefix == base_prefix: + branches.append(kbranch) + continue + + if (kbranch.find("/") != -1 and + (kbranch.find("standard") != -1 or kbranch.find("base") != -1) or + kbranch == "base"): + branches.append(kbranch) + continue + + return branches -- cgit v1.2.3-54-g00ecf