diff options
Diffstat (limited to 'meta/lib/oeqa/utils/commands.py')
| -rw-r--r-- | meta/lib/oeqa/utils/commands.py | 54 |
1 files changed, 50 insertions, 4 deletions
diff --git a/meta/lib/oeqa/utils/commands.py b/meta/lib/oeqa/utils/commands.py index 575e380017..9154220968 100644 --- a/meta/lib/oeqa/utils/commands.py +++ b/meta/lib/oeqa/utils/commands.py | |||
| @@ -203,6 +203,8 @@ def runCmd(command, ignore_status=False, timeout=None, assert_error=True, sync=T | |||
| 203 | 203 | ||
| 204 | if result.status and not ignore_status: | 204 | if result.status and not ignore_status: |
| 205 | exc_output = result.output | 205 | exc_output = result.output |
| 206 | if result.error: | ||
| 207 | exc_output = exc_output + result.error | ||
| 206 | if limit_exc_output > 0: | 208 | if limit_exc_output > 0: |
| 207 | split = result.output.splitlines() | 209 | split = result.output.splitlines() |
| 208 | if len(split) > limit_exc_output: | 210 | if len(split) > limit_exc_output: |
| @@ -283,7 +285,20 @@ def get_bb_vars(variables=None, target=None, postconfig=None): | |||
| 283 | return values | 285 | return values |
| 284 | 286 | ||
| 285 | def get_bb_var(var, target=None, postconfig=None): | 287 | def get_bb_var(var, target=None, postconfig=None): |
| 286 | return get_bb_vars([var], target, postconfig)[var] | 288 | if postconfig: |
| 289 | return bitbake("-e %s" % target or "", postconfig=postconfig).output | ||
| 290 | else: | ||
| 291 | # Fast-path for the non-postconfig case | ||
| 292 | cmd = ["bitbake-getvar", "--quiet", "--value", var] | ||
| 293 | if target: | ||
| 294 | cmd.extend(["--recipe", target]) | ||
| 295 | try: | ||
| 296 | return subprocess.run(cmd, check=True, text=True, stdout=subprocess.PIPE).stdout.strip() | ||
| 297 | except subprocess.CalledProcessError as e: | ||
| 298 | # We need to return None not the empty string if the variable hasn't been set. | ||
| 299 | if e.returncode == 1: | ||
| 300 | return None | ||
| 301 | raise | ||
| 287 | 302 | ||
| 288 | def get_test_layer(bblayers=None): | 303 | def get_test_layer(bblayers=None): |
| 289 | if bblayers is None: | 304 | if bblayers is None: |
| @@ -312,9 +327,26 @@ def create_temp_layer(templayerdir, templayername, priority=999, recipepathspec= | |||
| 312 | f.write('LAYERSERIES_COMPAT_%s = "%s"\n' % (templayername, corenames)) | 327 | f.write('LAYERSERIES_COMPAT_%s = "%s"\n' % (templayername, corenames)) |
| 313 | 328 | ||
| 314 | @contextlib.contextmanager | 329 | @contextlib.contextmanager |
| 315 | def runqemu(pn, ssh=True, runqemuparams='', image_fstype=None, launch_cmd=None, qemuparams=None, overrides={}, discard_writes=True): | 330 | def runqemu(pn, ssh=True, runqemuparams='', image_fstype=None, launch_cmd=None, qemuparams=None, overrides={}, boot_patterns = {}, discard_writes=True): |
| 316 | """ | 331 | """ |
| 317 | launch_cmd means directly run the command, don't need set rootfs or env vars. | 332 | Starts a context manager for a 'oeqa.targetcontrol.QemuTarget' resource. |
| 333 | The underlying Qemu will be booted into a shell when the generator yields | ||
| 334 | and stopped when the 'with' block exits. | ||
| 335 | |||
| 336 | Usage: | ||
| 337 | |||
| 338 | with runqemu('core-image-minimal') as qemu: | ||
| 339 | qemu.run_serial('cat /proc/cpuinfo') | ||
| 340 | |||
| 341 | Args: | ||
| 342 | pn (str): (image) recipe to run on | ||
| 343 | ssh (boolean): whether or not to enable SSH (network access) | ||
| 344 | runqemuparams (str): space-separated list of params to pass to 'runqemu' script (like 'nographics', 'ovmf', etc.) | ||
| 345 | image_fstype (str): IMAGE_FSTYPE to use | ||
| 346 | launch_cmd (str): directly run this command and bypass automatic runqemu parameter generation | ||
| 347 | overrides (dict): dict of "'<bitbake-variable>': value" pairs that allows overriding bitbake variables | ||
| 348 | boot_patterns (dict): dict of "'<pattern-name>': value" pairs to override default boot patterns, e.g. when not booting Linux | ||
| 349 | discard_writes (boolean): enables qemu -snapshot feature to prevent modifying original image | ||
| 318 | """ | 350 | """ |
| 319 | 351 | ||
| 320 | import bb.tinfoil | 352 | import bb.tinfoil |
| @@ -345,7 +377,7 @@ def runqemu(pn, ssh=True, runqemuparams='', image_fstype=None, launch_cmd=None, | |||
| 345 | 377 | ||
| 346 | logdir = recipedata.getVar("TEST_LOG_DIR") | 378 | logdir = recipedata.getVar("TEST_LOG_DIR") |
| 347 | 379 | ||
| 348 | qemu = oeqa.targetcontrol.QemuTarget(recipedata, targetlogger, image_fstype) | 380 | qemu = oeqa.targetcontrol.QemuTarget(recipedata, targetlogger, image_fstype, boot_patterns=boot_patterns) |
| 349 | finally: | 381 | finally: |
| 350 | # We need to shut down tinfoil early here in case we actually want | 382 | # We need to shut down tinfoil early here in case we actually want |
| 351 | # to run tinfoil-using utilities with the running QEMU instance. | 383 | # to run tinfoil-using utilities with the running QEMU instance. |
| @@ -369,6 +401,20 @@ def runqemu(pn, ssh=True, runqemuparams='', image_fstype=None, launch_cmd=None, | |||
| 369 | targetlogger.removeHandler(handler) | 401 | targetlogger.removeHandler(handler) |
| 370 | qemu.stop() | 402 | qemu.stop() |
| 371 | 403 | ||
| 404 | def runqemu_check_taps(): | ||
| 405 | """Check if tap devices for runqemu are available""" | ||
| 406 | if not os.path.exists('/etc/runqemu-nosudo'): | ||
| 407 | return False | ||
| 408 | result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ip tuntap show mode tap', ignore_status=True) | ||
| 409 | if result.status != 0: | ||
| 410 | return False | ||
| 411 | for line in result.output.splitlines(): | ||
| 412 | if 'tap' in line: | ||
| 413 | break | ||
| 414 | else: | ||
| 415 | return False | ||
| 416 | return True | ||
| 417 | |||
| 372 | def updateEnv(env_file): | 418 | def updateEnv(env_file): |
| 373 | """ | 419 | """ |
| 374 | Source a file and update environment. | 420 | Source a file and update environment. |
