Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release manifests #91

Merged
merged 8 commits into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 41 additions & 3 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ jobs:
done

# Build it
python3 tools/build_project.py \
/opt/venv/bin/python3 tools/build_project.py \
$sdk_args \
$toolchain_args \
--manifest "${{ matrix.manifest }}" \
Expand Down Expand Up @@ -188,14 +188,50 @@ jobs:
compression-level: 9
if-no-files-found: error

generate-manifest:
name: Generate manifest
needs: [build-container, build-firmwares]
runs-on: ubuntu-latest
container:
image: ${{ needs.build-container.outputs.container_name }}
options: --user root
steps:
- uses: actions/checkout@v4

- name: Download all workflow artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
merge-multiple: true
pattern: firmware-build-*

- name: Generate manifest
run: |
/opt/venv/bin/python3 tools/create_manifest.py artifacts > artifacts/manifest.json

- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: manifest
path: artifacts/manifest.json
compression-level: 9
if-no-files-found: error

release-assets:
name: Upload release assets
needs: [build-firmwares]
needs: [generate-manifest]
if: github.event_name == 'release'
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Download manifest
uses: actions/download-artifact@v4
with:
path: artifacts
merge-multiple: true
pattern: manifest

- name: Download all workflow artifacts
uses: actions/download-artifact@v4
with:
Expand All @@ -206,4 +242,6 @@ jobs:
- name: Upload artifacts
uses: softprops/action-gh-release@v2
with:
files: artifacts/*.gbl
files: |
artifacts/*.gbl
artifacts/manifest.json
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.4.3
rev: v0.7.3
hooks:
- id: ruff
args: [--fix]
Expand Down
10 changes: 9 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,18 @@ RUN \
default-jre-headless \
patch \
python3 \
python3-ruamel.yaml \
python3-pip \
python3-virtualenv \
unzip \
xz-utils

COPY requirements.txt /tmp/

RUN \
virtualenv /opt/venv \
&& /opt/venv/bin/pip install -r /tmp/requirements.txt \
&& rm /tmp/requirements.txt

# Install Simplicity Commander (unfortunately no stable URL available, this
# is known to be working with Commander_linux_x86_64_1v15p0b1306.tar.bz).
RUN \
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ tool will automatically determine which SDK and toolchain to use.
> automatically found so these flags can be omitted.

```bash
pip install ruamel.yaml # Only dependency
pip install -r requirements.txt

python tools/build_project.py \
# The following SDK and toolchain flags can be omitted on macOS
Expand Down
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ruamel.yaml
universal-silabs-flasher>=0.0.25
10 changes: 7 additions & 3 deletions tools/build_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from __future__ import annotations

import os
import re
import ast
import sys
Expand Down Expand Up @@ -169,9 +170,9 @@ def load_toolchains(paths: list[pathlib.Path]) -> dict[pathlib.Path, str]:
return toolchains


def subprocess_run_verbose(command: list[str], prefix: str) -> None:
def subprocess_run_verbose(command: list[str], prefix: str, **kwargs) -> None:
with subprocess.Popen(
command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT
command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, **kwargs
) as proc:
for line in proc.stdout:
LOGGER.info("[%s] %r", prefix, line.decode("utf-8").strip())
Expand Down Expand Up @@ -543,7 +544,10 @@ def main():
f"POST_BUILD_EXE={args.postbuild}",
"VERBOSE=1",
],
"make"
"make",
env={
"PATH": f"{pathlib.Path(sys.executable).parent}:{os.environ['PATH']}"
}
)
# fmt: on

Expand Down
67 changes: 67 additions & 0 deletions tools/create_manifest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#!/usr/bin/env python3
"""Tool to create a JSON manifest file for a collection of firmwares."""

from __future__ import annotations

import json
import logging
import hashlib
import pathlib
import argparse

from datetime import datetime, timezone

from universal_silabs_flasher.firmware import parse_firmware_image

_LOGGER = logging.getLogger(__name__)


def main():
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
parser.add_argument(
"firmware_dir",
type=pathlib.Path,
help="Directory containing firmware images",
)

args = parser.parse_args()
manifest = {
"metadata": {
"created_at": datetime.now(timezone.utc).isoformat(),
},
"firmwares": [],
}

for firmware_file in args.firmware_dir.glob("*.gbl"):
data = firmware_file.read_bytes()

try:
firmware = parse_firmware_image(data)
except ValueError:
_LOGGER.warning("Ignoring invalid firmware file: %s", firmware_file)
continue

try:
gbl_metadata = firmware.get_nabucasa_metadata()
except (KeyError, ValueError):
metadata = None
else:
metadata = gbl_metadata.original_json

manifest["firmwares"].append(
{
"filename": firmware_file.name,
"checksum": f"sha3-256:{hashlib.sha3_256(data).hexdigest()}",
"size": len(data),
"metadata": metadata,
"release_notes": None,
}
)

print(json.dumps(manifest, indent=2))


if __name__ == "__main__":
main()
Loading