1# 2# Copyright OpenEmbedded Contributors 3# 4# SPDX-License-Identifier: GPL-2.0-only 5# 6 7import logging 8import os 9import sys 10import os.path 11 12import bb.utils 13 14from bblayers.common import LayerPlugin 15 16logger = logging.getLogger('bitbake-config-layers') 17 18sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) 19 20def plugin_init(plugins): 21 return ConfigFragmentsPlugin() 22 23class ConfigFragmentsPlugin(LayerPlugin): 24 def get_fragment_info(self, path, name): 25 d = bb.data.init() 26 d.setVar('BBPATH', self.tinfoil.config_data.getVar('BBPATH')) 27 bb.parse.handle(path, d, True) 28 summary = d.getVar('BB_CONF_FRAGMENT_SUMMARY') 29 description = d.getVar('BB_CONF_FRAGMENT_DESCRIPTION') 30 if not summary: 31 raise Exception('Please add a one-line summary as BB_CONF_FRAGMENT_SUMMARY = \"...\" variable at the beginning of {}'.format(path)) 32 33 if not description: 34 raise Exception('Please add a description as BB_CONF_FRAGMENT_DESCRIPTION = \"...\" variable at the beginning of {}'.format(path)) 35 36 return summary, description 37 38 def discover_fragments(self): 39 fragments_path_prefix = self.tinfoil.config_data.getVar('OE_FRAGMENTS_PREFIX') 40 allfragments = {} 41 for layername in self.bbfile_collections: 42 layerdir = self.bbfile_collections[layername] 43 fragments = [] 44 for topdir, dirs, files in os.walk(os.path.join(layerdir, fragments_path_prefix)): 45 fragmentdir = os.path.relpath(topdir, os.path.join(layerdir, fragments_path_prefix)) 46 for fragmentfile in sorted(files): 47 if fragmentfile.startswith(".") or not fragmentfile.endswith(".conf"): 48 continue 49 fragmentname = os.path.normpath("/".join((layername, fragmentdir, fragmentfile.split('.')[0]))) 50 fragmentpath = os.path.join(topdir, fragmentfile) 51 fragmentsummary, fragmentdesc = self.get_fragment_info(fragmentpath, fragmentname) 52 fragments.append({'path':fragmentpath, 'name':fragmentname, 'summary':fragmentsummary, 'description':fragmentdesc}) 53 if fragments: 54 allfragments[layername] = {'layerdir':layerdir,'fragments':fragments} 55 return allfragments 56 57 def do_list_fragments(self, args): 58 """ List available configuration fragments """ 59 def print_fragment(f, verbose, is_enabled): 60 if not verbose: 61 print('{}\t{}'.format(f['name'], f['summary'])) 62 else: 63 print('Name: {}\nPath: {}\nEnabled: {}\nSummary: {}\nDescription:\n{}\n'.format(f['name'], f['path'], 'yes' if is_enabled else 'no', f['summary'],''.join(f['description']))) 64 65 all_enabled_fragments = (self.tinfoil.config_data.getVar('OE_FRAGMENTS') or "").split() 66 67 for layername, layerdata in self.discover_fragments().items(): 68 layerdir = layerdata['layerdir'] 69 fragments = layerdata['fragments'] 70 enabled_fragments = [f for f in fragments if f['name'] in all_enabled_fragments] 71 disabled_fragments = [f for f in fragments if f['name'] not in all_enabled_fragments] 72 73 print('Available fragments in {} layer located in {}:\n'.format(layername, layerdir)) 74 if enabled_fragments: 75 print('Enabled fragments:') 76 for f in enabled_fragments: 77 print_fragment(f, args.verbose, is_enabled=True) 78 print('') 79 if disabled_fragments: 80 print('Unused fragments:') 81 for f in disabled_fragments: 82 print_fragment(f, args.verbose, is_enabled=False) 83 print('') 84 85 def fragment_exists(self, fragmentname): 86 for layername, layerdata in self.discover_fragments().items(): 87 for f in layerdata['fragments']: 88 if f['name'] == fragmentname: 89 return True 90 return False 91 92 def create_conf(self, confpath): 93 if not os.path.exists(confpath): 94 with open(confpath, 'w') as f: 95 f.write('') 96 with open(confpath, 'r') as f: 97 lines = f.read() 98 if "OE_FRAGMENTS += " not in lines: 99 lines += "\nOE_FRAGMENTS += \"\"\n" 100 with open(confpath, 'w') as f: 101 f.write(lines) 102 103 def do_enable_fragment(self, args): 104 """ Enable a fragment in the local build configuration """ 105 def enable_helper(varname, origvalue, op, newlines): 106 enabled_fragments = origvalue.split() 107 for f in args.fragmentname: 108 if f in enabled_fragments: 109 print("Fragment {} already included in {}".format(f, args.confpath)) 110 else: 111 enabled_fragments.append(f) 112 return " ".join(enabled_fragments), None, 0, True 113 114 for f in args.fragmentname: 115 if not self.fragment_exists(f): 116 raise Exception("Fragment {} does not exist; use 'list-fragments' to see the full list.".format(f)) 117 118 self.create_conf(args.confpath) 119 modified = bb.utils.edit_metadata_file(args.confpath, ["OE_FRAGMENTS"], enable_helper) 120 if modified: 121 print("Fragment {} added to {}.".format(", ".join(args.fragmentname), args.confpath)) 122 123 def do_disable_fragment(self, args): 124 """ Disable a fragment in the local build configuration """ 125 def disable_helper(varname, origvalue, op, newlines): 126 enabled_fragments = origvalue.split() 127 for f in args.fragmentname: 128 if f in enabled_fragments: 129 enabled_fragments.remove(f) 130 else: 131 print("Fragment {} not currently enabled in {}".format(f, args.confpath)) 132 return " ".join(enabled_fragments), None, 0, True 133 134 self.create_conf(args.confpath) 135 modified = bb.utils.edit_metadata_file(args.confpath, ["OE_FRAGMENTS"], disable_helper) 136 if modified: 137 print("Fragment {} removed from {}.".format(", ".join(args.fragmentname), args.confpath)) 138 139 def do_disable_all_fragments(self, args): 140 """ Disable all fragments in the local build configuration """ 141 def disable_all_helper(varname, origvalue, op, newlines): 142 return "", None, 0, True 143 144 self.create_conf(args.confpath) 145 modified = bb.utils.edit_metadata_file(args.confpath, ["OE_FRAGMENTS"], disable_all_helper) 146 if modified: 147 print("All fragments removed from {}.".format(args.confpath)) 148 149 def register_commands(self, sp): 150 default_confpath = os.path.join(os.environ["BBPATH"], "conf/auto.conf") 151 152 parser_list_fragments = self.add_command(sp, 'list-fragments', self.do_list_fragments, parserecipes=False) 153 parser_list_fragments.add_argument("--confpath", default=default_confpath, help='Configuration file which contains a list of enabled fragments (default is {}).'.format(default_confpath)) 154 parser_list_fragments.add_argument('--verbose', '-v', action='store_true', help='Print extended descriptions of the fragments') 155 156 parser_enable_fragment = self.add_command(sp, 'enable-fragment', self.do_enable_fragment, parserecipes=False) 157 parser_enable_fragment.add_argument("--confpath", default=default_confpath, help='Configuration file which contains a list of enabled fragments (default is {}).'.format(default_confpath)) 158 parser_enable_fragment.add_argument('fragmentname', help='The name of the fragment (use list-fragments to see them)', nargs='+') 159 160 parser_disable_fragment = self.add_command(sp, 'disable-fragment', self.do_disable_fragment, parserecipes=False) 161 parser_disable_fragment.add_argument("--confpath", default=default_confpath, help='Configuration file which contains a list of enabled fragments (default is {}).'.format(default_confpath)) 162 parser_disable_fragment.add_argument('fragmentname', help='The name of the fragment', nargs='+') 163 164 parser_disable_all = self.add_command(sp, 'disable-all-fragments', self.do_disable_all_fragments, parserecipes=False) 165 parser_disable_all.add_argument("--confpath", default=default_confpath, help='Configuration file which contains a list of enabled fragments (default is {}).'.format(default_confpath)) 166