scripts: runner: generalize commands to "capabilities"

Some configuration options or device tree nodes affect the way that
runners ought to behave, but there's no good way for them to report
whether they can handle them.

One motivating example is CONFIG_FLASH_LOAD_OFFSET, as influenced by
the zephyr,code-partition chosen node in the DT for architectures
where CONFIG_HAS_FLASH_LOAD_OFFSET=y.

If CONFIG_FLASH_LOAD_OFFSET is nonzero, the 'flash' command ought to
place the kernel at that address offset from the device flash's start
address. Runners don't support this right now, which should be
fixed. However, we don't want to mandate support for this feature,
since not all targets need it.

We need to let runners declare what their capabilities are. Make it so
by adding a RunnerCaps class to the runner core. This currently just
states which commands a runner can handle, but can be generalized to
implement the above use case.

Signed-off-by: Marti Bolivar <marti@opensourcefoundries.com>
This commit is contained in:
Marti Bolivar 2017-11-16 14:31:29 -05:00 committed by Anas Nashif
commit cd8d43b1c9
7 changed files with 42 additions and 27 deletions

View file

@ -8,7 +8,7 @@ from os import path
import os
import platform
from .core import ZephyrBinaryRunner, get_env_or_bail
from .core import ZephyrBinaryRunner, RunnerCaps, get_env_or_bail
DEFAULT_BOSSAC_PORT = '/dev/ttyACM0'
@ -28,8 +28,8 @@ class BossacBinaryRunner(ZephyrBinaryRunner):
return 'bossac'
@classmethod
def handles_command(cls, command):
return command == 'flash'
def capabilities(cls):
return RunnerCaps(commands={'flash'})
def create_from_env(command, debug):
'''Create flasher from environment.

View file

@ -143,6 +143,17 @@ class NetworkPortHelper:
return {int(b) for b in used_bytes}
class RunnerCaps:
'''This class represents a runner class's capabilities.
The most basic capability is the set of supported commands,
available in the commands field. This defaults to all three
commands.'''
def __init__(self, commands={'flash', 'debug', 'debugserver'}):
self.commands = commands
class ZephyrBinaryRunner(abc.ABC):
'''Abstract superclass for binary runners (flashers, debuggers).
@ -184,7 +195,7 @@ class ZephyrBinaryRunner(abc.ABC):
1. Define a ZephyrBinaryRunner subclass, and implement its
abstract methods. Override any methods you need to, especially
handles_command().
capabilities().
2. Make sure the Python module defining your runner class is
imported by this package's __init__.py (otherwise,
@ -229,7 +240,8 @@ class ZephyrBinaryRunner(abc.ABC):
else:
raise ValueError('no runner named {} is known'.format(runner_name))
if not cls.handles_command(command):
caps = cls.capabilities()
if command not in caps.commands:
raise ValueError('runner {} does not implement command {}'.format(
runner_name, command))
@ -246,13 +258,15 @@ class ZephyrBinaryRunner(abc.ABC):
etc.).'''
@classmethod
def handles_command(cls, command):
'''Return True iff this class can run the given command.
def capabilities(cls):
'''Returns a RunnerCaps representing this runner's capabilities.
The default implementation returns True if the command is
valid (i.e. is one of "flash", "debug", and "debugserver").
Subclasses should override if they only provide a subset.'''
return command in {'flash', 'debug', 'debugserver'}
This implementation returns the default capabilities, which
includes support for all three commands, but no other special
powers.
Subclasses should override appropriately if needed.'''
return RunnerCaps()
@staticmethod
@abc.abstractmethod
@ -263,7 +277,8 @@ class ZephyrBinaryRunner(abc.ABC):
'''Runs command ('flash', 'debug', 'debugserver').
This is the main entry point to this runner.'''
if not self.handles_command(command):
caps = self.capabilities()
if command not in caps.commands:
raise ValueError('runner {} does not implement command {}'.format(
self.name(), command))
self.do_run(command, **kwargs)

View file

@ -8,7 +8,7 @@ import os
import sys
import time
from .core import ZephyrBinaryRunner, get_env_or_bail
from .core import ZephyrBinaryRunner, RunnerCaps, get_env_or_bail
class DfuUtilBinaryRunner(ZephyrBinaryRunner):
@ -30,8 +30,8 @@ class DfuUtilBinaryRunner(ZephyrBinaryRunner):
return 'dfu-util'
@classmethod
def handles_command(cls, command):
return command == 'flash'
def capabilities(cls):
return RunnerCaps(commands={'flash'})
def create_from_env(command, debug):
'''Create flasher from environment.

View file

@ -7,7 +7,7 @@
from os import path
import os
from .core import ZephyrBinaryRunner, get_env_or_bail
from .core import ZephyrBinaryRunner, RunnerCaps, get_env_or_bail
class Esp32BinaryRunner(ZephyrBinaryRunner):
@ -30,8 +30,8 @@ class Esp32BinaryRunner(ZephyrBinaryRunner):
return 'esp32'
@classmethod
def handles_command(cls, command):
return command == 'flash'
def capabilities(cls):
return RunnerCaps(commands={'flash'})
def create_from_env(command, debug):
'''Create flasher from environment.

View file

@ -7,7 +7,7 @@
from os import path
import os
from .core import ZephyrBinaryRunner, get_env_or_bail
from .core import ZephyrBinaryRunner, RunnerCaps, get_env_or_bail
DEFAULT_JLINK_GDB_PORT = 2331
@ -33,8 +33,8 @@ class JLinkBinaryRunner(ZephyrBinaryRunner):
return 'jlink'
@classmethod
def handles_command(cls, command):
return command in {'debug', 'debugserver'}
def capabilities(cls):
return RunnerCaps(commands={'debug', 'debugserver'})
def create_from_env(command, debug):
'''Create runner from environment.

View file

@ -7,7 +7,7 @@
from os import path
import sys
from .core import ZephyrBinaryRunner, get_env_or_bail
from .core import ZephyrBinaryRunner, RunnerCaps, get_env_or_bail
class NrfJprogBinaryRunner(ZephyrBinaryRunner):
@ -23,8 +23,8 @@ class NrfJprogBinaryRunner(ZephyrBinaryRunner):
return 'nrfjprog'
@classmethod
def handles_command(cls, command):
return command == 'flash'
def capabilities(cls):
return RunnerCaps(commands={'flash'})
def create_from_env(command, debug):
'''Create flasher from environment.

View file

@ -6,7 +6,7 @@
from os import path
from .core import ZephyrBinaryRunner, get_env_or_bail
from .core import ZephyrBinaryRunner, RunnerCaps, get_env_or_bail
class XtensaBinaryRunner(ZephyrBinaryRunner):
@ -22,8 +22,8 @@ class XtensaBinaryRunner(ZephyrBinaryRunner):
return 'xtensa'
@classmethod
def handles_command(cls, command):
return command == 'debug'
def capabilities(cls):
return RunnerCaps(commands={'debug'})
def create_from_env(command, debug):
'''Create runner from environment.