build: interpose zephyr_flash_debug.py in flash target

Zephyr board flashing and debugging is done via shell scripts. It
would improve the CMake transition to remove the shell dependency.

Add zephyr_flash_debug.py to allow phasing out the shell scripts.
This takes two arguments:

- a command (eventually flash, debug, and debugserver, but just flash
  for now)

- the path to the corresponding shell script

zephyr_flash_debug.py runs the command in pure Python if it
knows how. Otherwise, it falls back on the shell script. In
this patch, it always falls back. Subsequent patches add support
for existing flash backends.

Invoke zephyr_flash_debug.py from the Makefile flash target, but only
if USE_ZEPHYR_FLASH_DEBUG_SHELL is empty. This lets users keep existing
behavior in case of issues, and can be removed later once the Python
script is more widely tested.

Signed-off-by: Marti Bolivar <marti.bolivar@linaro.org>
This commit is contained in:
Marti Bolivar 2017-10-09 22:59:50 -04:00 committed by Andrew Boie
parent c136a2eb83
commit 113ee65b89
2 changed files with 111 additions and 0 deletions

View file

@ -1374,9 +1374,15 @@ run:
endif
ifneq ($(FLASH_SCRIPT),)
ifeq ($(USE_ZEPHYR_FLASH_DEBUG_SHELL),)
flash: zephyr
@echo "Flashing $(BOARD_NAME)"
$(Q)$(srctree)/scripts/support/zephyr_flash_debug.py flash $(srctree)/scripts/support/$(FLASH_SCRIPT)
else
flash: zephyr
@echo "Flashing $(BOARD_NAME)"
$(Q)$(CONFIG_SHELL) $(srctree)/scripts/support/$(FLASH_SCRIPT) flash
endif
else
flash: FORCE
@echo Flashing not supported with this board.

View file

@ -0,0 +1,105 @@
#! /usr/bin/env python3
# Copyright (c) 2017 Linaro Limited.
#
# SPDX-License-Identifier: Apache-2.0
"""Zephyr board flashing script
This script is a transparent replacement for an existing Zephyr flash
script. If it can invoke the flashing tools natively, it will do so; otherwise,
it delegates to the shell script passed as second argument."""
import abc
from os import path
import os
import sys
import subprocess
def get_env_bool_or(env_var, default_value):
try:
return bool(int(os.environ[env_var]))
except KeyError:
return default_value
def check_call(cmd, debug):
if debug:
print(' '.join(cmd))
subprocess.check_call(cmd)
class ZephyrBinaryFlasher(abc.ABC):
'''Abstract superclass for flasher objects.'''
def __init__(self, debug=False):
self.debug = debug
@staticmethod
def create_for_shell_script(shell_script, debug):
'''Factory for using as a drop-in replacement to a shell script.
Get flasher instance to use in place of shell_script, deriving
flasher configuration from the environment.'''
for sub_cls in ZephyrBinaryFlasher.__subclasses__():
if sub_cls.replaces_shell_script(shell_script):
return sub_cls.create_from_env(debug)
raise ValueError('no flasher replaces script {}'.format(shell_script))
@staticmethod
@abc.abstractmethod
def replaces_shell_script(shell_script):
'''Check if this flasher class replaces FLASH_SCRIPT=shell_script.'''
@staticmethod
@abc.abstractmethod
def create_from_env(debug):
'''Create new flasher instance from environment variables.
This class must be able to replace the current FLASH_SCRIPT. The
environment variables expected by that script are used to build
the flasher in a backwards-compatible manner.'''
@abc.abstractmethod
def flash(self, **kwargs):
'''Flash the board.'''
# TODO: Stop using environment variables.
#
# Migrate the build system so we can use an argparse.ArgumentParser and
# per-flasher subparsers, so invoking the script becomes something like:
#
# python zephyr_flash_debug.py openocd --openocd-bin=/openocd/path ...
#
# For now, maintain compatibility.
def flash(shell_script_full, debug):
shell_script = path.basename(shell_script_full)
try:
flasher = ZephyrBinaryFlasher.create_for_shell_script(shell_script,
debug)
except ValueError:
# Can't create a flasher; fall back on shell script.
check_call([shell_script_full, 'flash'], debug)
return
flasher.flash()
if __name__ == '__main__':
debug = True
try:
debug = get_env_bool_or('KBUILD_VERBOSE', False)
if len(sys.argv) != 3 or sys.argv[1] != 'flash':
raise ValueError('usage: {} flash path-to-script'.format(
sys.argv[0]))
flash(sys.argv[2], debug)
except Exception as e:
if debug:
raise
else:
print('Error: {}'.format(e), file=sys.stderr)
print('Re-run with KBUILD_VERBOSE=1 for a stack trace.',
file=sys.stderr)
sys.exit(1)