diff options
Diffstat (limited to 'meta/lib/bbconfigbuild')
-rw-r--r-- | meta/lib/bbconfigbuild/configfragments.py | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/meta/lib/bbconfigbuild/configfragments.py b/meta/lib/bbconfigbuild/configfragments.py new file mode 100644 index 0000000000..61c33ac316 --- /dev/null +++ b/meta/lib/bbconfigbuild/configfragments.py | |||
@@ -0,0 +1,185 @@ | |||
1 | # | ||
2 | # Copyright OpenEmbedded Contributors | ||
3 | # | ||
4 | # SPDX-License-Identifier: GPL-2.0-only | ||
5 | # | ||
6 | |||
7 | import logging | ||
8 | import os | ||
9 | import sys | ||
10 | import os.path | ||
11 | |||
12 | import bb.utils | ||
13 | |||
14 | from bblayers.common import LayerPlugin | ||
15 | |||
16 | logger = logging.getLogger('bitbake-config-layers') | ||
17 | |||
18 | sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) | ||
19 | |||
20 | def plugin_init(plugins): | ||
21 | return ConfigFragmentsPlugin() | ||
22 | |||
23 | class 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 | def print_builtin_fragments(builtin, enabled): | ||
66 | print('Available built-in fragments:') | ||
67 | builtin_dict = {i[0]:i[1] for i in [f.split(':') for f in builtin]} | ||
68 | for prefix,var in builtin_dict.items(): | ||
69 | print('{}/...\tSets {} = ...'.format(prefix, var)) | ||
70 | print('') | ||
71 | enabled_builtin_fragments = [f for f in enabled if self.builtin_fragment_exists(f)] | ||
72 | print('Enabled built-in fragments:') | ||
73 | for f in enabled_builtin_fragments: | ||
74 | prefix, value = f.split('/', 1) | ||
75 | print('{}\tSets {} = "{}"'.format(f, builtin_dict[prefix], value)) | ||
76 | print('') | ||
77 | |||
78 | all_enabled_fragments = (self.tinfoil.config_data.getVar('OE_FRAGMENTS') or "").split() | ||
79 | all_builtin_fragments = (self.tinfoil.config_data.getVar('OE_FRAGMENTS_BUILTIN') or "").split() | ||
80 | print_builtin_fragments(all_builtin_fragments, all_enabled_fragments) | ||
81 | |||
82 | for layername, layerdata in self.discover_fragments().items(): | ||
83 | layerdir = layerdata['layerdir'] | ||
84 | fragments = layerdata['fragments'] | ||
85 | enabled_fragments = [f for f in fragments if f['name'] in all_enabled_fragments] | ||
86 | disabled_fragments = [f for f in fragments if f['name'] not in all_enabled_fragments] | ||
87 | |||
88 | print('Available fragments in {} layer located in {}:\n'.format(layername, layerdir)) | ||
89 | if enabled_fragments: | ||
90 | print('Enabled fragments:') | ||
91 | for f in enabled_fragments: | ||
92 | print_fragment(f, args.verbose, is_enabled=True) | ||
93 | print('') | ||
94 | if disabled_fragments: | ||
95 | print('Unused fragments:') | ||
96 | for f in disabled_fragments: | ||
97 | print_fragment(f, args.verbose, is_enabled=False) | ||
98 | print('') | ||
99 | |||
100 | def fragment_exists(self, fragmentname): | ||
101 | for layername, layerdata in self.discover_fragments().items(): | ||
102 | for f in layerdata['fragments']: | ||
103 | if f['name'] == fragmentname: | ||
104 | return True | ||
105 | return False | ||
106 | |||
107 | def builtin_fragment_exists(self, fragmentname): | ||
108 | fragment_prefix = fragmentname.split("/",1)[0] | ||
109 | fragment_prefix_defs = set([f.split(':')[0] for f in self.tinfoil.config_data.getVar('OE_FRAGMENTS_BUILTIN').split()]) | ||
110 | return fragment_prefix in fragment_prefix_defs | ||
111 | |||
112 | def create_conf(self, confpath): | ||
113 | if not os.path.exists(confpath): | ||
114 | with open(confpath, 'w') as f: | ||
115 | f.write('') | ||
116 | with open(confpath, 'r') as f: | ||
117 | lines = f.read() | ||
118 | if "OE_FRAGMENTS += " not in lines: | ||
119 | lines += "\nOE_FRAGMENTS += \"\"\n" | ||
120 | with open(confpath, 'w') as f: | ||
121 | f.write(lines) | ||
122 | |||
123 | def do_enable_fragment(self, args): | ||
124 | """ Enable a fragment in the local build configuration """ | ||
125 | def enable_helper(varname, origvalue, op, newlines): | ||
126 | enabled_fragments = origvalue.split() | ||
127 | for f in args.fragmentname: | ||
128 | if f in enabled_fragments: | ||
129 | print("Fragment {} already included in {}".format(f, args.confpath)) | ||
130 | else: | ||
131 | enabled_fragments.append(f) | ||
132 | return " ".join(enabled_fragments), None, 0, True | ||
133 | |||
134 | for f in args.fragmentname: | ||
135 | if not self.fragment_exists(f) and not self.builtin_fragment_exists(f): | ||
136 | raise Exception("Fragment {} does not exist; use 'list-fragments' to see the full list.".format(f)) | ||
137 | |||
138 | self.create_conf(args.confpath) | ||
139 | modified = bb.utils.edit_metadata_file(args.confpath, ["OE_FRAGMENTS"], enable_helper) | ||
140 | if modified: | ||
141 | print("Fragment {} added to {}.".format(", ".join(args.fragmentname), args.confpath)) | ||
142 | |||
143 | def do_disable_fragment(self, args): | ||
144 | """ Disable a fragment in the local build configuration """ | ||
145 | def disable_helper(varname, origvalue, op, newlines): | ||
146 | enabled_fragments = origvalue.split() | ||
147 | for f in args.fragmentname: | ||
148 | if f in enabled_fragments: | ||
149 | enabled_fragments.remove(f) | ||
150 | else: | ||
151 | print("Fragment {} not currently enabled in {}".format(f, args.confpath)) | ||
152 | return " ".join(enabled_fragments), None, 0, True | ||
153 | |||
154 | self.create_conf(args.confpath) | ||
155 | modified = bb.utils.edit_metadata_file(args.confpath, ["OE_FRAGMENTS"], disable_helper) | ||
156 | if modified: | ||
157 | print("Fragment {} removed from {}.".format(", ".join(args.fragmentname), args.confpath)) | ||
158 | |||
159 | def do_disable_all_fragments(self, args): | ||
160 | """ Disable all fragments in the local build configuration """ | ||
161 | def disable_all_helper(varname, origvalue, op, newlines): | ||
162 | return "", None, 0, True | ||
163 | |||
164 | self.create_conf(args.confpath) | ||
165 | modified = bb.utils.edit_metadata_file(args.confpath, ["OE_FRAGMENTS"], disable_all_helper) | ||
166 | if modified: | ||
167 | print("All fragments removed from {}.".format(args.confpath)) | ||
168 | |||
169 | def register_commands(self, sp): | ||
170 | default_confpath = os.path.join(os.environ["BBPATH"], "conf/auto.conf") | ||
171 | |||
172 | parser_list_fragments = self.add_command(sp, 'list-fragments', self.do_list_fragments, parserecipes=False) | ||
173 | parser_list_fragments.add_argument("--confpath", default=default_confpath, help='Configuration file which contains a list of enabled fragments (default is {}).'.format(default_confpath)) | ||
174 | parser_list_fragments.add_argument('--verbose', '-v', action='store_true', help='Print extended descriptions of the fragments') | ||
175 | |||
176 | parser_enable_fragment = self.add_command(sp, 'enable-fragment', self.do_enable_fragment, parserecipes=False) | ||
177 | parser_enable_fragment.add_argument("--confpath", default=default_confpath, help='Configuration file which contains a list of enabled fragments (default is {}).'.format(default_confpath)) | ||
178 | parser_enable_fragment.add_argument('fragmentname', help='The name of the fragment (use list-fragments to see them)', nargs='+') | ||
179 | |||
180 | parser_disable_fragment = self.add_command(sp, 'disable-fragment', self.do_disable_fragment, parserecipes=False) | ||
181 | parser_disable_fragment.add_argument("--confpath", default=default_confpath, help='Configuration file which contains a list of enabled fragments (default is {}).'.format(default_confpath)) | ||
182 | parser_disable_fragment.add_argument('fragmentname', help='The name of the fragment', nargs='+') | ||
183 | |||
184 | parser_disable_all = self.add_command(sp, 'disable-all-fragments', self.do_disable_all_fragments, parserecipes=False) | ||
185 | parser_disable_all.add_argument("--confpath", default=default_confpath, help='Configuration file which contains a list of enabled fragments (default is {}).'.format(default_confpath)) | ||