diff --git a/.bandit b/.bandit new file mode 100644 index 00000000..eec99a94 --- /dev/null +++ b/.bandit @@ -0,0 +1,3 @@ +# Ignore B404 "Avoid importing subprocess" +# Ignore B603 "Subprocess without shell equals true" +skips: ['B404', 'B603'] diff --git a/.travis.yml b/.travis.yml index e627821a..22c62479 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,7 +26,7 @@ jobs: - stage: Test env: BUILDER_ENV=travis-2_3_0 - env: BUILDER_ENV=travis-latest - - env: BUILDER_ENV=travis-git BUILDER_EXTRA=secure_client + - env: BUILDER_ENV=travis-git BUILDER_EXTRA="-a test/build/extra/secure_client.h" - stage: Release env: BUILDER_THREAD=0 - env: BUILDER_THREAD=1 diff --git a/code/scripts/espurna_utils/__init__.py b/code/scripts/espurna_utils/__init__.py index 62387a3c..174e56aa 100644 --- a/code/scripts/espurna_utils/__init__.py +++ b/code/scripts/espurna_utils/__init__.py @@ -1,3 +1,24 @@ +# coding=utf-8 +# +# Original extra_scripts.py +# Copyright (C) 2016-2019 by Xose PĂ©rez +# +# ldscripts, lwip patching, updated postmortem flags and git support +# Copyright (C) 2019 by Maxim Prokhorov +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + from .checks import check_cppcheck, check_printsize from .float_support import remove_float_support from .ldscripts import ldscripts_inject_libpath diff --git a/code/scripts/espurna_utils/display.py b/code/scripts/espurna_utils/display.py index 0628f94b..0e614b66 100644 --- a/code/scripts/espurna_utils/display.py +++ b/code/scripts/espurna_utils/display.py @@ -1,10 +1,11 @@ from __future__ import print_function +import os import sys -import click class Color(object): + BOLD = "\x1b[1;1m" BLACK = "\x1b[1;30m" RED = "\x1b[1;31m" GREEN = "\x1b[1;32m" @@ -31,8 +32,13 @@ def print_warning(message, color=Color.LIGHT_YELLOW): print(clr(color, message), file=sys.stderr) -def print_filler(fill, color=Color.WHITE, err=False): - width, _ = click.get_terminal_size() +def print_filler(fill, color=Color.WHITE, err=False, width_default=80): + width = width_default + try: + width = int(os.environ["COLUMNS"]) + except (KeyError, ValueError): + pass + if len(fill) > 1: fill = fill[0] diff --git a/code/scripts/test_build.py b/code/scripts/test_build.py new file mode 100755 index 00000000..c65c984a --- /dev/null +++ b/code/scripts/test_build.py @@ -0,0 +1,133 @@ +#!/usr/bin/env python +# +# Copyright (C) 2019 by Maxim Prokhorov +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from __future__ import print_function + +import time +import glob +import argparse +import atexit +import subprocess +import os +import sys +import datetime +from espurna_utils.display import Color, clr, print_warning + +CUSTOM_HEADER = "espurna/config/custom.h" +if os.path.exists(CUSTOM_HEADER): + raise SystemExit( + clr( + Color.YELLOW, + "{} already exists, please run this script in a git-worktree(1) or a separate directory".format( + CUSTOM_HEADER + ), + ) + ) + + +def try_remove(path): + try: + os.remove(path) + except: # pylint: disable=bare-except + print_warning("Please manually remove the file `{}`".format(path)) + + +atexit.register(try_remove, CUSTOM_HEADER) + + +def main(args): + configurations = [] + if not args.no_default: + configurations = list(glob.glob(args.default_configurations)) + + configurations.extend(x for x in (args.add or [])) + if not configurations: + raise SystemExit(clr(Color.YELLOW, "No configurations selected")) + + print(clr(Color.BOLD, "> Selected configurations:")) + for cfg in configurations: + print(cfg) + if args.list: + return + + if not args.environment: + raise SystemExit(clr(Color.YELLOW, "No environment selected")) + print(clr(Color.BOLD, "> Selected environment: {}".format(args.environment))) + + for cfg in configurations: + print(clr(Color.BOLD, "> Building {}".format(cfg))) + with open(CUSTOM_HEADER, "w") as custom_h: + + def write(line): + sys.stdout.write(line) + custom_h.write(line) + + name, _ = os.path.splitext(cfg) + name = os.path.basename(name) + write('#define MANUFACTURER "TEST_BUILD"\n') + write('#define DEVICE "{}"\n'.format(name.upper())) + with open(cfg, "r") as cfg_file: + for line in cfg_file: + write(line) + + os_env = os.environ.copy() + os_env["PLATFORMIO_SRC_BUILD_FLAGS"] = "-DUSE_CUSTOM_H" + os_env["PLATFORMIO_BUILD_CACHE_DIR"] = "test/pio_cache" + cmd = ["platformio", "run", "-s", "-e", args.environment] + + start = time.time() + subprocess.check_call(cmd, env=os_env) + end = time.time() + print( + clr( + Color.BOLD, + "> {}: {} bytes, {}".format( + cfg, + os.stat( + os.path.join(".pio", "build", args.environment, "firmware.bin") + ).st_size, + datetime.timedelta(seconds=(end - start)), + ), + ) + ) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument( + "-l", "--list", action="store_true", help="List selected configurations" + ) + parser.add_argument( + "-n", + "--no-default", + action="store_true", + help="Do not use default configurations (--default-configurations=...)", + ) + parser.add_argument( + "-a", + "--add", + action="append", + help="Add path to selected configurations (can specify multiple times)", + ) + parser.add_argument("-e", "--environment", help="PIO environment") + parser.add_argument( + "--default-configurations", + default="test/build/*.h", + help="(glob) default configuration headers", + ) + + main(parser.parse_args()) diff --git a/code/test/build/secure_client.h b/code/test/build/extra/secure_client.h similarity index 100% rename from code/test/build/secure_client.h rename to code/test/build/extra/secure_client.h diff --git a/code/test_build.sh b/code/test_build.sh deleted file mode 100755 index 7fef5b8b..00000000 --- a/code/test_build.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash - -set -eu -o pipefail - -CUSTOM_HEADER="espurna/config/custom.h" -TARGET_ENVIRONMENT=${1:?"pio env name"} -shift 1 - -CONFIGURATIONS=( - basic - sensor - emon - light_my92xx - light_dimmer - nondefault -) - -if [ $# > 0 ] ; then - CONFIGURATIONS=("${CONFIGURATIONS[@]}" "$@") -fi - -trap 'rm -f ${CUSTOM_HEADER}' EXIT - -for cfg in "${CONFIGURATIONS[@]}" ; do - echo "travis_fold:start:build_${cfg}" - echo "- building ${cfg}" - - printf "#define MANUFACTURER \"%s\"\n" "TEST_BUILD" \ - | tee ${CUSTOM_HEADER} - printf "#define DEVICE \"%s\"\n" "${cfg^^}" \ - | tee --append ${CUSTOM_HEADER} - tee --append ${CUSTOM_HEADER} < "test/build/${cfg}.h" - - export PLATFORMIO_SRC_BUILD_FLAGS="-DUSE_CUSTOM_H" - export PLATFORMIO_BUILD_CACHE_DIR="test/pio_cache" - - time pio run -s -e "$TARGET_ENVIRONMENT" - echo "travis_fold:end:build_${cfg}" -done diff --git a/travis_script.sh b/travis_script.sh index 4621fcc0..21eaf7e3 100755 --- a/travis_script.sh +++ b/travis_script.sh @@ -5,7 +5,7 @@ set -e -v cd code if [ ${TRAVIS_BUILD_STAGE_NAME} = "Test" ]; then - ./test_build.sh $BUILDER_ENV $BUILDER_EXTRA + scripts/test_build.py -e $BUILDER_ENV $BUILDER_EXTRA else ./build.sh -p fi