summaryrefslogtreecommitdiffstats
path: root/scripts/devtool
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/devtool')
-rwxr-xr-xscripts/devtool88
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
10import dataclasses
10import sys 11import sys
11import os 12import os
12import argparse 13import argparse
13import glob 14import glob
14import re 15import re
15import configparser 16import configparser
16import subprocess
17import logging 17import logging
18 18
19basepath = '' 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
20workspace = {} 20from typing import List
21config = None
22context = None
23 21
24 22
25scripts_path = os.path.dirname(os.path.realpath(__file__)) 23scripts_path = os.path.dirname(os.path.realpath(__file__))
@@ -30,16 +28,16 @@ import scriptutils
30import argparse_oe 28import argparse_oe
31logger = scriptutils.logger_create('devtool') 29logger = scriptutils.logger_create('devtool')
32 30
33plugins = []
34 31
35 32class ConfigHandler:
36class 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
84class Context: 84class 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
89def read_workspace(): 90def 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
135def create_workspace(args, config, basepath, workspace): 135 return workspace
136
137def 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
147def _create_workspace(workspacedir, config, basepath, layerseries=None): 149def _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
191def _enable_workspace_layer(workspacedir, config, basepath): 193def _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
211def main(): 213def 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