Files
espurna/code/scripts/generate_release_sh.py
Maxim Prokhorov 4c33cacfdb pio: add build-and-copy, more configuration options for version
Multiple ways to specify version string through environment variables:
- `ESPURNA_BUILD_FULL_VERSION` to set full version string
By default it is empty, and the version is combined using the values specified below
- `ESPURNA_BUILD_VERSION` to modify the first part of the version string (1.15.0-dev)
By default, uses espurna/config/version.h APP_VERSION value
- `ESPURNA_BUILD_REVISION` to specify revision part of the version string
For example 12345678, which is expanded as either .git12345678 or -git12345678
(depending on whether the version string contains hyphen)
By default, use git to retrieve the first 8 characters of the current HEAD SHA value
- `ESPURNA_BUILD_VERSION_SUFFIX` to specify build metadata part of the string
For example nightly20210607, which is added to the full version as 1.15.0-dev+nightly20210607
Empty by defauld

Adds -t build-and-copy which uses the values above to copy firmware.bin, configurable with:
- `ESPURNA_BUILD_NAME` to set the suffix of the filename.
By default, uses the $PIOENV (aka the string after the env: in the .ini file)
- `ESPURNA_BUILD_DESTINATION` to specify where to copy the .bin files
By default, uses $PROJECT_DIR

Resulting file is stored at:
${ESPURNA_BUILD_DESTINATION}/${ESPURNA_BUILD_FULL_VERSION}/espurna-${ESPURNA_BUILD_FULL_VERSION}-${ESPURNA_BUILD_NAME}.bin

In addition, modify generate_release_sh.py to use the new environment variables.
2021-06-07 03:54:28 +03:00

193 lines
6.0 KiB
Python
Executable File

#!/usr/bin/env python
#
# Copyright (C) 2020 by Maxim Prokhorov <prokhorov dot max at outlook dot com>
#
# 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 <http://www.gnu.org/licenses/>.
import argparse
import re
import shlex
import configparser
import collections
Build = collections.namedtuple("Build", "env extends build_flags src_build_flags")
def expand_variables(cfg, value):
RE_VARS = re.compile("\$\{.*?\}")
for var in RE_VARS.findall(value):
section, option = var.replace("${", "").replace("}", "").split(".", 1)
value = value.replace(var, expand_variables(cfg, cfg.get(section, option)))
return value
def get_builds(cfg):
RE_NEWLINE = re.compile("\r\n|\n")
BASE_BUILD_FLAGS = set(
shlex.split(expand_variables(cfg, cfg.get("env", "build_flags")))
)
for section in cfg.sections():
if (not section.startswith("env:")) or (
section.startswith("env:esp8266-") and section.endswith("-base")
):
continue
build_flags = None
src_build_flags = None
try:
build_flags = cfg.get(section, "build_flags")
build_flags = RE_NEWLINE.sub(" ", build_flags).strip()
build_flags = " ".join(
BASE_BUILD_FLAGS ^ set(shlex.split(expand_variables(cfg, build_flags)))
)
except configparser.NoOptionError:
pass
try:
src_build_flags = cfg.get(section, "src_build_flags")
src_build_flags = RE_NEWLINE.sub(" ", src_build_flags).strip()
src_build_flags = expand_variables(cfg, src_build_flags)
except configparser.NoOptionError:
pass
yield Build(
section.replace("env:", ""),
cfg.get(section, "extends").replace("env:", ""),
build_flags,
src_build_flags,
)
def find_any(string, values):
for value in values:
if value in string:
return True
return False
def generate_lines(builds, ignore):
cores = []
generic = []
for build in builds:
if find_any(build.env, ignore):
continue
flags = []
if build.build_flags:
flags.append('PLATFORMIO_BUILD_FLAGS="{}"'.format(build.build_flags))
if build.src_build_flags:
flags.append('ESPURNA_FLAGS="{}"'.format(build.src_build_flags))
flags.append('ESPURNA_BUILD_NAME="{env}"'.format(env=build.env))
cmd = ["env"]
cmd.extend(flags)
cmd.extend(["pio", "run", "-e", build.extends, "-s", "-t", "build-and-copy"])
line = " ".join(cmd)
# push core variants to the front as they definetly include global build_flags
output = generic
if "ESPURNA_CORE" in build.src_build_flags:
output = cores
output.append(line)
return cores + generic
def every(seq, nth, total):
index = 0
for value in seq:
if index == nth:
yield value
index = (index + 1) % total
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument(
"--destination", help="Where to place the resulting .bin", required=True
)
parser.add_argument(
"--single-source",
help="Combine .cpp files into one to speed up compilation",
default=True,
)
parser.add_argument(
"--ignore", help="Do not build envs that contain the string(s)", action="append"
)
builder_thread = parser.add_argument_group(
title="Builder thread control for CI parallel builds"
)
builder_thread.add_argument("--builder-thread", type=int, required=True)
builder_thread.add_argument("--builder-total-threads", type=int, required=True)
full_version = parser.add_argument_group(
title="Fully replace the version string for the build system"
)
full_version.add_argument("--full-version")
version_parts = parser.add_argument_group(
"Replace parts of the version string that would have been detected by the build system"
)
version_parts.add_argument("--version")
version_parts.add_argument("--revision")
version_parts.add_argument("--suffix")
parser.parse_args()
if __name__ == "__main__":
args = parse_args()
Config = configparser.ConfigParser()
with open("platformio.ini", "r") as f:
Config.read_file(f)
builder_total_threads = args.builder_total_threads
builder_thread = args.builder_thread
if builder_thread >= builder_total_threads:
raise ValueError("* Builder thread index out of range *")
builds = every(get_builds(Config), builder_thread, builder_total_threads)
print("#!/bin/bash")
print("set -e -x")
print('export ESPURNA_BUILD_DESTINATION="{}"'.format(args.destination))
print("export ESPURNA_BUILD_SINGLE_SOURCE={}".format(int(args.single_source)))
if args.full_version:
print('export ESPURNA_BUILD_FULL_VERSION="{}"'.format(args.full_version))
else:
if args.version:
print('export ESPURNA_BUILD_VERSION="{}"'.format(args.version))
if args.suffix:
print('export ESPURNA_BUILD_REVISION="{}"'.format(args.revision))
if args.suffix:
print('export ESPURNA_BUILD_VERSION_SUFFIX="{}"'.format(args.suffix))
print('trap "ls -R ${ESPURNA_BUILD_DESTINATION}" EXIT')
print(
'echo "Selected thread #{} out of {}"'.format(
builder_thread + 1, builder_total_threads
)
)
for line in generate_lines(builds, args.ignore or ()):
print(line)