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 | ||
