diff options
Diffstat (limited to 'scripts/devtool')
-rwxr-xr-x | scripts/devtool | 88 |
1 files changed, 45 insertions, 43 deletions
diff --git a/scripts/devtool b/scripts/devtool index 60ea3e8298..39cebec0d8 100755 --- a/scripts/devtool +++ b/scripts/devtool | |||
@@ -7,19 +7,17 @@ | |||
7 | # SPDX-License-Identifier: GPL-2.0-only | 7 | # SPDX-License-Identifier: GPL-2.0-only |
8 | # | 8 | # |
9 | 9 | ||
10 | import dataclasses | ||
10 | import sys | 11 | import sys |
11 | import os | 12 | import os |
12 | import argparse | 13 | import argparse |
13 | import glob | 14 | import glob |
14 | import re | 15 | import re |
15 | import configparser | 16 | import configparser |
16 | import subprocess | ||
17 | import logging | 17 | import logging |
18 | 18 | ||
19 | basepath = '' | 19 | # This can be removed once our minimum is Python 3.9: https://docs.python.org/3/whatsnew/3.9.html#type-hinting-generics-in-standard-collections |
20 | workspace = {} | 20 | from typing import List |
21 | config = None | ||
22 | context = None | ||
23 | 21 | ||
24 | 22 | ||
25 | scripts_path = os.path.dirname(os.path.realpath(__file__)) | 23 | scripts_path = os.path.dirname(os.path.realpath(__file__)) |
@@ -30,16 +28,16 @@ import scriptutils | |||
30 | import argparse_oe | 28 | import argparse_oe |
31 | logger = scriptutils.logger_create('devtool') | 29 | logger = scriptutils.logger_create('devtool') |
32 | 30 | ||
33 | plugins = [] | ||
34 | 31 | ||
35 | 32 | class ConfigHandler: | |
36 | class ConfigHandler(object): | 33 | basepath = None |
37 | config_file = '' | 34 | config_file = '' |
38 | config_obj = None | 35 | config_obj = None |
39 | init_path = '' | 36 | init_path = '' |
40 | workspace_path = '' | 37 | workspace_path = '' |
41 | 38 | ||
42 | def __init__(self, filename): | 39 | def __init__(self, basepath, filename): |
40 | self.basepath = basepath | ||
43 | self.config_file = filename | 41 | self.config_file = filename |
44 | self.config_obj = configparser.ConfigParser() | 42 | self.config_obj = configparser.ConfigParser() |
45 | 43 | ||
@@ -47,7 +45,7 @@ class ConfigHandler(object): | |||
47 | try: | 45 | try: |
48 | ret = self.config_obj.get(section, option) | 46 | ret = self.config_obj.get(section, option) |
49 | except (configparser.NoOptionError, configparser.NoSectionError): | 47 | except (configparser.NoOptionError, configparser.NoSectionError): |
50 | if default != None: | 48 | if default is not None: |
51 | ret = default | 49 | ret = default |
52 | else: | 50 | else: |
53 | raise | 51 | raise |
@@ -59,14 +57,14 @@ class ConfigHandler(object): | |||
59 | 57 | ||
60 | if self.config_obj.has_option('General', 'init_path'): | 58 | if self.config_obj.has_option('General', 'init_path'): |
61 | pth = self.get('General', 'init_path') | 59 | pth = self.get('General', 'init_path') |
62 | self.init_path = os.path.join(basepath, pth) | 60 | self.init_path = os.path.join(self.basepath, pth) |
63 | if not os.path.exists(self.init_path): | 61 | if not os.path.exists(self.init_path): |
64 | logger.error('init_path %s specified in config file cannot be found' % pth) | 62 | logger.error('init_path %s specified in config file cannot be found' % pth) |
65 | return False | 63 | return False |
66 | else: | 64 | else: |
67 | self.config_obj.add_section('General') | 65 | self.config_obj.add_section('General') |
68 | 66 | ||
69 | self.workspace_path = self.get('General', 'workspace_path', os.path.join(basepath, 'workspace')) | 67 | self.workspace_path = self.get('General', 'workspace_path', os.path.join(self.basepath, 'workspace')) |
70 | return True | 68 | return True |
71 | 69 | ||
72 | 70 | ||
@@ -81,27 +79,29 @@ class ConfigHandler(object): | |||
81 | self.config_obj.add_section(section) | 79 | self.config_obj.add_section(section) |
82 | self.config_obj.set(section, option, value) | 80 | self.config_obj.set(section, option, value) |
83 | 81 | ||
82 | |||
83 | @dataclasses.dataclass | ||
84 | class Context: | 84 | class Context: |
85 | def __init__(self, **kwargs): | 85 | fixed_setup: bool |
86 | self.__dict__.update(kwargs) | 86 | config: ConfigHandler |
87 | pluginpaths: List[str] | ||
87 | 88 | ||
88 | 89 | ||
89 | def read_workspace(): | 90 | def read_workspace(basepath, context): |
90 | global workspace | ||
91 | workspace = {} | 91 | workspace = {} |
92 | if not os.path.exists(os.path.join(config.workspace_path, 'conf', 'layer.conf')): | 92 | if not os.path.exists(os.path.join(context.config.workspace_path, 'conf', 'layer.conf')): |
93 | if context.fixed_setup: | 93 | if context.fixed_setup: |
94 | logger.error("workspace layer not set up") | 94 | logger.error("workspace layer not set up") |
95 | sys.exit(1) | 95 | sys.exit(1) |
96 | else: | 96 | else: |
97 | logger.info('Creating workspace layer in %s' % config.workspace_path) | 97 | logger.info('Creating workspace layer in %s' % context.config.workspace_path) |
98 | _create_workspace(config.workspace_path, config, basepath) | 98 | _create_workspace(context.config.workspace_path, basepath) |
99 | if not context.fixed_setup: | 99 | if not context.fixed_setup: |
100 | _enable_workspace_layer(config.workspace_path, config, basepath) | 100 | _enable_workspace_layer(context.config.workspace_path, context.config, basepath) |
101 | 101 | ||
102 | logger.debug('Reading workspace in %s' % config.workspace_path) | 102 | logger.debug('Reading workspace in %s' % context.config.workspace_path) |
103 | externalsrc_re = re.compile(r'^EXTERNALSRC(:pn-([^ =]+))? *= *"([^"]*)"$') | 103 | externalsrc_re = re.compile(r'^EXTERNALSRC(:pn-([^ =]+))? *= *"([^"]*)"$') |
104 | for fn in glob.glob(os.path.join(config.workspace_path, 'appends', '*.bbappend')): | 104 | for fn in glob.glob(os.path.join(context.config.workspace_path, 'appends', '*.bbappend')): |
105 | with open(fn, 'r') as f: | 105 | with open(fn, 'r') as f: |
106 | pnvalues = {} | 106 | pnvalues = {} |
107 | pn = None | 107 | pn = None |
@@ -112,7 +112,7 @@ def read_workspace(): | |||
112 | pn = res.group(2) or recipepn | 112 | pn = res.group(2) or recipepn |
113 | # Find the recipe file within the workspace, if any | 113 | # Find the recipe file within the workspace, if any |
114 | bbfile = os.path.basename(fn).replace('.bbappend', '.bb').replace('%', '*') | 114 | bbfile = os.path.basename(fn).replace('.bbappend', '.bb').replace('%', '*') |
115 | recipefile = glob.glob(os.path.join(config.workspace_path, | 115 | recipefile = glob.glob(os.path.join(context.config.workspace_path, |
116 | 'recipes', | 116 | 'recipes', |
117 | recipepn, | 117 | recipepn, |
118 | bbfile)) | 118 | bbfile)) |
@@ -126,13 +126,15 @@ def read_workspace(): | |||
126 | if pnvalues: | 126 | if pnvalues: |
127 | if not pn: | 127 | if not pn: |
128 | raise DevtoolError("Found *.bbappend in %s, but could not determine EXTERNALSRC:pn-*. " | 128 | raise DevtoolError("Found *.bbappend in %s, but could not determine EXTERNALSRC:pn-*. " |
129 | "Maybe still using old syntax?" % config.workspace_path) | 129 | "Maybe still using old syntax?" % context.config.workspace_path) |
130 | if not pnvalues.get('srctreebase', None): | 130 | if not pnvalues.get('srctreebase', None): |
131 | pnvalues['srctreebase'] = pnvalues['srctree'] | 131 | pnvalues['srctreebase'] = pnvalues['srctree'] |
132 | logger.debug('Found recipe %s' % pnvalues) | 132 | logger.debug('Found recipe %s' % pnvalues) |
133 | workspace[pn] = pnvalues | 133 | workspace[pn] = pnvalues |
134 | 134 | ||
135 | def create_workspace(args, config, basepath, workspace): | 135 | return workspace |
136 | |||
137 | def create_workspace(args, config, basepath, _workspace): | ||
136 | if args.layerpath: | 138 | if args.layerpath: |
137 | workspacedir = os.path.abspath(args.layerpath) | 139 | workspacedir = os.path.abspath(args.layerpath) |
138 | else: | 140 | else: |
@@ -140,12 +142,12 @@ def create_workspace(args, config, basepath, workspace): | |||
140 | layerseries = None | 142 | layerseries = None |
141 | if args.layerseries: | 143 | if args.layerseries: |
142 | layerseries = args.layerseries | 144 | layerseries = args.layerseries |
143 | _create_workspace(workspacedir, config, basepath, layerseries) | 145 | _create_workspace(workspacedir, basepath, layerseries) |
144 | if not args.create_only: | 146 | if not args.create_only: |
145 | _enable_workspace_layer(workspacedir, config, basepath) | 147 | _enable_workspace_layer(workspacedir, config, basepath) |
146 | 148 | ||
147 | def _create_workspace(workspacedir, config, basepath, layerseries=None): | 149 | def _create_workspace(workspacedir, basepath, layerseries=None): |
148 | import bb | 150 | import bb.utils |
149 | 151 | ||
150 | confdir = os.path.join(workspacedir, 'conf') | 152 | confdir = os.path.join(workspacedir, 'conf') |
151 | if os.path.exists(os.path.join(confdir, 'layer.conf')): | 153 | if os.path.exists(os.path.join(confdir, 'layer.conf')): |
@@ -190,7 +192,7 @@ def _create_workspace(workspacedir, config, basepath, layerseries=None): | |||
190 | 192 | ||
191 | def _enable_workspace_layer(workspacedir, config, basepath): | 193 | def _enable_workspace_layer(workspacedir, config, basepath): |
192 | """Ensure the workspace layer is in bblayers.conf""" | 194 | """Ensure the workspace layer is in bblayers.conf""" |
193 | import bb | 195 | import bb.utils |
194 | bblayers_conf = os.path.join(basepath, 'conf', 'bblayers.conf') | 196 | bblayers_conf = os.path.join(basepath, 'conf', 'bblayers.conf') |
195 | if not os.path.exists(bblayers_conf): | 197 | if not os.path.exists(bblayers_conf): |
196 | logger.error('Unable to find bblayers.conf') | 198 | logger.error('Unable to find bblayers.conf') |
@@ -209,15 +211,9 @@ def _enable_workspace_layer(workspacedir, config, basepath): | |||
209 | 211 | ||
210 | 212 | ||
211 | def main(): | 213 | def main(): |
212 | global basepath | ||
213 | global config | ||
214 | global context | ||
215 | |||
216 | if sys.getfilesystemencoding() != "utf-8": | 214 | if sys.getfilesystemencoding() != "utf-8": |
217 | sys.exit("Please use a locale setting which supports utf-8.\nPython can't change the filesystem locale after loading so we need a utf-8 when python starts or things won't work.") | 215 | sys.exit("Please use a locale setting which supports utf-8.\nPython can't change the filesystem locale after loading so we need a utf-8 when python starts or things won't work.") |
218 | 216 | ||
219 | context = Context(fixed_setup=False) | ||
220 | |||
221 | # Default basepath | 217 | # Default basepath |
222 | basepath = os.path.dirname(os.path.abspath(__file__)) | 218 | basepath = os.path.dirname(os.path.abspath(__file__)) |
223 | 219 | ||
@@ -242,21 +238,23 @@ def main(): | |||
242 | elif global_args.quiet: | 238 | elif global_args.quiet: |
243 | logger.setLevel(logging.ERROR) | 239 | logger.setLevel(logging.ERROR) |
244 | 240 | ||
241 | is_fixed_setup = False | ||
242 | |||
245 | if global_args.basepath: | 243 | if global_args.basepath: |
246 | # Override | 244 | # Override |
247 | basepath = global_args.basepath | 245 | basepath = global_args.basepath |
248 | if os.path.exists(os.path.join(basepath, '.devtoolbase')): | 246 | if os.path.exists(os.path.join(basepath, '.devtoolbase')): |
249 | context.fixed_setup = True | 247 | is_fixed_setup = True |
250 | else: | 248 | else: |
251 | pth = basepath | 249 | pth = basepath |
252 | while pth != '' and pth != os.sep: | 250 | while pth != '' and pth != os.sep: |
253 | if os.path.exists(os.path.join(pth, '.devtoolbase')): | 251 | if os.path.exists(os.path.join(pth, '.devtoolbase')): |
254 | context.fixed_setup = True | 252 | is_fixed_setup = True |
255 | basepath = pth | 253 | basepath = pth |
256 | break | 254 | break |
257 | pth = os.path.dirname(pth) | 255 | pth = os.path.dirname(pth) |
258 | 256 | ||
259 | if not context.fixed_setup: | 257 | if not is_fixed_setup: |
260 | basepath = os.environ.get('BUILDDIR') | 258 | basepath = os.environ.get('BUILDDIR') |
261 | if not basepath: | 259 | if not basepath: |
262 | logger.error("This script can only be run after initialising the build environment (e.g. by using oe-init-build-env)") | 260 | logger.error("This script can only be run after initialising the build environment (e.g. by using oe-init-build-env)") |
@@ -264,10 +262,9 @@ def main(): | |||
264 | 262 | ||
265 | logger.debug('Using basepath %s' % basepath) | 263 | logger.debug('Using basepath %s' % basepath) |
266 | 264 | ||
267 | config = ConfigHandler(os.path.join(basepath, 'conf', 'devtool.conf')) | 265 | config = ConfigHandler(basepath, os.path.join(basepath, 'conf', 'devtool.conf')) |
268 | if not config.read(): | 266 | if not config.read(): |
269 | return -1 | 267 | return -1 |
270 | context.config = config | ||
271 | 268 | ||
272 | bitbake_subdir = config.get('General', 'bitbake_subdir', '') | 269 | bitbake_subdir = config.get('General', 'bitbake_subdir', '') |
273 | if bitbake_subdir: | 270 | if bitbake_subdir: |
@@ -289,6 +286,7 @@ def main(): | |||
289 | scriptutils.logger_setup_color(logger, global_args.color) | 286 | scriptutils.logger_setup_color(logger, global_args.color) |
290 | 287 | ||
291 | if global_args.bbpath is None: | 288 | if global_args.bbpath is None: |
289 | import bb | ||
292 | try: | 290 | try: |
293 | tinfoil = setup_tinfoil(config_only=True, basepath=basepath) | 291 | tinfoil = setup_tinfoil(config_only=True, basepath=basepath) |
294 | try: | 292 | try: |
@@ -300,7 +298,10 @@ def main(): | |||
300 | 298 | ||
301 | # Search BBPATH first to allow layers to override plugins in scripts_path | 299 | # Search BBPATH first to allow layers to override plugins in scripts_path |
302 | pluginpaths = [os.path.join(path, 'lib', 'devtool') for path in global_args.bbpath.split(':') + [scripts_path]] | 300 | pluginpaths = [os.path.join(path, 'lib', 'devtool') for path in global_args.bbpath.split(':') + [scripts_path]] |
303 | context.pluginpaths = pluginpaths | 301 | |
302 | context = Context(fixed_setup=is_fixed_setup, config=config, pluginpaths=pluginpaths) | ||
303 | |||
304 | plugins = [] | ||
304 | for pluginpath in pluginpaths: | 305 | for pluginpath in pluginpaths: |
305 | scriptutils.load_plugins(logger, plugins, pluginpath) | 306 | scriptutils.load_plugins(logger, plugins, pluginpath) |
306 | 307 | ||
@@ -331,9 +332,9 @@ def main(): | |||
331 | args = parser.parse_args(unparsed_args, namespace=global_args) | 332 | args = parser.parse_args(unparsed_args, namespace=global_args) |
332 | 333 | ||
333 | try: | 334 | try: |
335 | workspace = {} | ||
334 | if not getattr(args, 'no_workspace', False): | 336 | if not getattr(args, 'no_workspace', False): |
335 | read_workspace() | 337 | workspace = read_workspace(basepath, context) |
336 | |||
337 | ret = args.func(args, config, basepath, workspace) | 338 | ret = args.func(args, config, basepath, workspace) |
338 | except DevtoolError as err: | 339 | except DevtoolError as err: |
339 | if str(err): | 340 | if str(err): |
@@ -341,6 +342,7 @@ def main(): | |||
341 | ret = err.exitcode | 342 | ret = err.exitcode |
342 | except argparse_oe.ArgumentUsageError as ae: | 343 | except argparse_oe.ArgumentUsageError as ae: |
343 | parser.error_subcommand(ae.message, ae.subcommand) | 344 | parser.error_subcommand(ae.message, ae.subcommand) |
345 | ret = 2 | ||
344 | 346 | ||
345 | return ret | 347 | return ret |
346 | 348 | ||