scripts: runners: abstract jlink's missing program support

The runners/jlink.py script has a mechanism for erroring out if a host
tool is not installed. Abstract it into runners/core.py and handle it
from run_common.py. This will let it be used in more places.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
This commit is contained in:
Marti Bolivar 2019-05-25 15:41:36 -06:00 committed by Carles Cufí
commit c07267a26a
4 changed files with 39 additions and 10 deletions

View file

@ -17,7 +17,7 @@ from build_helpers import find_build_dir, is_zephyr_build, \
FIND_BUILD_DIR_DESCRIPTION
from west.commands import CommandContextError
from runners import get_runner_cls, ZephyrBinaryRunner
from runners import get_runner_cls, ZephyrBinaryRunner, MissingProgram
from zephyr_ext_common import cached_runner_config
@ -229,7 +229,11 @@ def do_run_common(command, args, runner_args, cached_runner_var):
if unknown:
log.die('Runner', runner, 'received unknown arguments:', unknown)
runner = runner_cls.create(cfg, parsed_args)
runner.run(command_name)
try:
runner.run(command_name)
except MissingProgram as e:
log.die('required program', e.filename,
'not found; install it or add its location to PATH')
#

View file

@ -2,7 +2,7 @@
#
# SPDX-License-Identifier: Apache-2.0
from runners.core import ZephyrBinaryRunner
from runners.core import ZephyrBinaryRunner, MissingProgram
# We import these here to ensure the ZephyrBinaryRunner subclasses are
# defined; otherwise, ZephyrBinaryRunner.create_for_shell_script()

View file

@ -13,8 +13,10 @@ as well as some other helpers for concrete runner classes.
import abc
import argparse
import errno
import os
import platform
import shutil
import signal
import subprocess
@ -157,6 +159,19 @@ class BuildConfiguration:
return value
class MissingProgram(FileNotFoundError):
'''FileNotFoundError subclass for missing program dependencies.
No significant changes from the parent FileNotFoundError; this is
useful for explicitly signaling that the file in question is a
program that some class requires to proceed.
The filename attribute contains the missing program.'''
def __init__(self, program):
super().__init__(errno.ENOENT, os.strerror(errno.ENOENT), program)
class RunnerCaps:
'''This class represents a runner class's capabilities.
@ -415,6 +430,20 @@ class ZephyrBinaryRunner(abc.ABC):
In case of an unsupported command, raise a ValueError.'''
def require(self, program):
'''Require that a program is installed before proceeding.
:param program: name of the program that is required,
or path to a program binary.
If ``program`` is an absolute path to an existing program
binary, this call succeeds. Otherwise, try to find the program
by name on the system PATH.
On error, raises MissingProgram.'''
if shutil.which(program) is None:
raise MissingProgram(program)
def run_server_and_client(self, server, client):
'''Run a server that ignores SIGINT, and a client that handles it.

View file

@ -107,10 +107,6 @@ class JLinkBinaryRunner(ZephyrBinaryRunner):
def print_gdbserver_message(self):
log.inf('J-Link GDB server running on port {}'.format(self.gdb_port))
def check_cmd(self, cmd):
if shutil.which(cmd) is None:
log.die('{} is not installed or cannot be found'.format(cmd))
def do_run(self, command, **kwargs):
server_cmd = ([self.gdbserver] +
['-select', 'usb', # only USB connections supported
@ -125,11 +121,11 @@ class JLinkBinaryRunner(ZephyrBinaryRunner):
if command == 'flash':
self.flash(**kwargs)
elif command == 'debugserver':
self.check_cmd(self.gdbserver)
self.require(self.gdbserver)
self.print_gdbserver_message()
self.check_call(server_cmd)
else:
self.check_cmd(self.gdbserver)
self.require(self.gdbserver)
if self.gdb_cmd is None:
raise ValueError('Cannot debug; gdb is missing')
if self.elf_name is None:
@ -149,7 +145,7 @@ class JLinkBinaryRunner(ZephyrBinaryRunner):
self.run_server_and_client(server_cmd, client_cmd)
def flash(self, **kwargs):
self.check_cmd(self.commander)
self.require(self.commander)
if self.bin_name is None:
raise ValueError('Cannot flash; bin_name is missing')