# 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(scripts_path): """ 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 = [] f = open(bblayers_conf, "r") lines = f.readlines() bblayers_lines = [] in_bblayers = False for line in lines: line = line.strip() tokens = line.split() if len(tokens) > 0 and tokens[0] == 'BBLAYERS': bblayers_lines.append(line) in_bblayers = True quotes = line.strip().count('"') if quotes > 1: in_bblayers = False continue if in_bblayers: bblayers_lines.append(line) if line.strip().endswith("\""): in_bblayers = False for i, line in enumerate(bblayers_lines): if line.strip().endswith("\\"): bblayers_lines[i] = line.strip().replace('\\', '') bblayers_line = " ".join(bblayers_lines) openquote = '' for c in bblayers_line: if c == '\"' or c == '\'': if openquote: if c != openquote: print "Invalid BBLAYERS found in %s, exiting" % bblayers_conf sys.exit(1) else: openquote = '' else: openquote = c if openquote: print "Invalid BBLAYERS found in %s, exiting" % bblayers_conf sys.exit(1) bblayers_line = bblayers_line.strip().replace('\"', '') bblayers_line = bblayers_line.strip().replace('\'', '') raw_layers = bblayers_line.split() for layer in raw_layers: if layer == 'BBLAYERS' or '=' in layer: continue layers.append(layer) f.close() return layers def find_meta_layer(scripts_path): """ Find and return the meta layer in BBLAYERS. """ layers = find_bblayers(scripts_path) for layer in layers: if layer.endswith("meta"): return layer return None def find_bsp_layer(scripts_path, machine): """ Find and return a machine's BSP layer in BBLAYERS. """ layers = find_bblayers(scripts_path) 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(scripts_path, 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(scripts_path, 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(scripts_path, 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(scripts_path) 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(scripts_path, 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(scripts_path, 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