Skip to content
Permalink
Browse files

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>
  • Loading branch information...
mbolivar authored and carlescufi committed May 25, 2019
1 parent db7b9a9 commit c07267a26a6edac8f1f5ffebd2836b0f5e8d97ad
@@ -17,7 +17,7 @@
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')


#
@@ -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()
@@ -13,8 +13,10 @@

import abc
import argparse
import errno
import os
import platform
import shutil
import signal
import subprocess

@@ -157,6 +159,19 @@ def _parse_value(self, value):
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 @@ def do_run(self, command, **kwargs):
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.
@@ -107,10 +107,6 @@ def create(cls, cfg, args):
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 @@ def do_run(self, command, **kwargs):
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 @@ def do_run(self, command, **kwargs):
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')

0 comments on commit c07267a

Please sign in to comment.
You can’t perform that action at this time.