* [PATCH 1/3] ci/listmachines: add helper to list machines in a layer
@ 2021-08-12 9:49 Ross Burton
2021-08-12 9:49 ` [PATCH 2/3] ci/check-machine-coverage: use listmachines.py Ross Burton
2021-08-12 9:49 ` [PATCH 3/3] scripts: add machine summary report tool Ross Burton
0 siblings, 2 replies; 3+ messages in thread
From: Ross Burton @ 2021-08-12 9:49 UTC (permalink / raw)
To: meta-arm
Instead of duplicating this logic, put it in a little helper module.
Change-Id: I2ca881c8de7e6ec6d4a940255d9ba97226e78d87
Signed-off-by: Ross Burton <ross.burton@arm.com>
---
ci/listmachines.py | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
create mode 100755 ci/listmachines.py
diff --git a/ci/listmachines.py b/ci/listmachines.py
new file mode 100755
index 0000000..04d207e
--- /dev/null
+++ b/ci/listmachines.py
@@ -0,0 +1,29 @@
+#! /usr/bin/env python3
+
+import pathlib
+import typing
+import sys
+
+"""
+List all of the machines available under the listed sub-layers of meta-arm.
+"""
+def list_machines(layers: typing.Sequence[str]) -> typing.Set[str]:
+ machines = set()
+
+ # We know we're in meta-arm/scripts, so find the top-level directory
+ metaarm = pathlib.Path(__file__).resolve().parent.parent
+ if metaarm.name != "meta-arm":
+ raise Exception("Not running inside meta-arm")
+
+ for layer in layers:
+ machines |= set(p.stem for p in (metaarm / layer / "conf" / "machine").glob("*.conf"))
+ return machines
+
+if __name__ == "__main__":
+ if len(sys.argv) > 1:
+ machines = list_machines(sys.argv[1:])
+ print(" ".join(sorted(machines)))
+ sys.exit(0)
+ else:
+ print("Usage:\n$ %s [layer name ...] " % sys.argv[0])
+ sys.exit(1)
--
2.25.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH 2/3] ci/check-machine-coverage: use listmachines.py
2021-08-12 9:49 [PATCH 1/3] ci/listmachines: add helper to list machines in a layer Ross Burton
@ 2021-08-12 9:49 ` Ross Burton
2021-08-12 9:49 ` [PATCH 3/3] scripts: add machine summary report tool Ross Burton
1 sibling, 0 replies; 3+ messages in thread
From: Ross Burton @ 2021-08-12 9:49 UTC (permalink / raw)
To: meta-arm
Change-Id: I5a7e706ae29b76a39aed8acfc0cd825e942b1cfe
Signed-off-by: Ross Burton <ross.burton@arm.com>
---
ci/check-machine-coverage | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/ci/check-machine-coverage b/ci/check-machine-coverage
index 035d421..f329fce 100755
--- a/ci/check-machine-coverage
+++ b/ci/check-machine-coverage
@@ -2,6 +2,7 @@
from pathlib import Path
import sys
+from listmachines import list_machines
metaarm = Path.cwd()
@@ -9,9 +10,10 @@ if metaarm.name != "meta-arm":
print("Not running inside meta-arm")
sys.exit(1)
+# Find all layers
+layers = (p.name for p in metaarm.glob("meta-*") if p.is_dir())
# All machine configurations
-machines = metaarm.glob("meta-*/conf/machine/*.conf")
-machines = set(p.stem for p in machines)
+machines = list_machines(layers)
# All kas files
kas = metaarm.glob("ci/*.yml")
--
2.25.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH 3/3] scripts: add machine summary report tool
2021-08-12 9:49 [PATCH 1/3] ci/listmachines: add helper to list machines in a layer Ross Burton
2021-08-12 9:49 ` [PATCH 2/3] ci/check-machine-coverage: use listmachines.py Ross Burton
@ 2021-08-12 9:49 ` Ross Burton
1 sibling, 0 replies; 3+ messages in thread
From: Ross Burton @ 2021-08-12 9:49 UTC (permalink / raw)
To: meta-arm
machine-summary.py is a tool to generate a report of what recipes and
versions are used for what machines, and what the latest upstream release
is.
Change-Id: Iecf21a14057df0fd1cb05be9b54c621dfbaddd94
Signed-off-by: Ross Burton <ross.burton@arm.com>
---
.gitlab-ci.yml | 8 ++
scripts/machine-summary-overview.txt.jinja | 12 ++
scripts/machine-summary-updates.html.jinja | 47 ++++++++
scripts/machine-summary.py | 122 +++++++++++++++++++++
4 files changed, 189 insertions(+)
create mode 100644 scripts/machine-summary-overview.txt.jinja
create mode 100644 scripts/machine-summary-updates.html.jinja
create mode 100755 scripts/machine-summary.py
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index bbd4c91..8ceb980 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -88,6 +88,14 @@ check-layers:
- kas shell --update --force-checkout ci/base.yml:ci/meta-arm-autonomy.yml:ci/meta-openembedded.yml --command \
"$CI_PROJECT_DIR/ci/check-layers.py $CI_PROJECT_DIR/ci/check-layers.yml $CI_PROJECT_DIR $KAS_WORK_DIR"
+pending-updates:
+ extends: .setup
+ artifacts:
+ paths:
+ - update-report.html
+ script:
+ - kas shell ci/qemuarm64.yml:ci/meta-openembedded.yml -c "$CI_PROJECT_DIR/scripts/machine-summary.py -t updates.html -o $CI_PROJECT_DIR/update-report.html $($CI_PROJECT_DIR/ci/listmachines.py meta-arm meta-arm-bsp)"
+
corstone500:
extends: .build
diff --git a/scripts/machine-summary-overview.txt.jinja b/scripts/machine-summary-overview.txt.jinja
new file mode 100644
index 0000000..d585065
--- /dev/null
+++ b/scripts/machine-summary-overview.txt.jinja
@@ -0,0 +1,12 @@
+Machine Overview
+Generated at {{ timestamp }}.
+{% for machine, data in data|dictsort %}
+
+MACHINE: {{ machine }}
+{% for recipe in recipes|sort %}
+{% if recipe in data %}
+{% set details = data[recipe] %}
+{{ details.recipe }}: {{ details.version }}
+{% endif %}
+{% endfor %}
+{% endfor %}
diff --git a/scripts/machine-summary-updates.html.jinja b/scripts/machine-summary-updates.html.jinja
new file mode 100644
index 0000000..d3ac2ff
--- /dev/null
+++ b/scripts/machine-summary-updates.html.jinja
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Pending Machine Upgrades Report</title>
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.1/css/bulma.min.css">
+ </head>
+ <body>
+ <section class="section">
+ <div class="content">
+ <h1 class="title">Pending Machine Upgrades Report</h1>
+ <p>Generated at {{ timestamp }}.</p>
+ </div>
+
+ <table class="table is-striped">
+ <thead>
+ <tr>
+ <th>Machine</th>
+ {% for recipe in recipes|sort %}
+ <th>{{ recipe }} ({{releases[recipe]|default("?")}})</th>
+ {% endfor %}
+ </tr>
+ </thead>
+ <tbody>
+ {% for machine, data in data|dictsort %}
+ <tr>
+ <th>{{ machine }}</th>
+ {% for recipe in recipes|sort %}
+ {% if recipe in data %}
+ {% set details = data[recipe] %}
+ {% set is_old = details.version is old(details.upstream) %}
+ <td class="{% if is_old %}has-text-weight-bold{% endif %}">
+ {{ details.recipe if details.recipe != recipe}}
+ {{ details.version }}
+ {{ "(patched)" if details.patched }}
+ </td>
+ {% else %}
+ <td>-</td>
+ {% endif %}
+ {% endfor %}
+ </tr>
+ {% endfor %}
+ </tbody>
+ </table>
+ </section>
+ </body>
+</html>
diff --git a/scripts/machine-summary.py b/scripts/machine-summary.py
new file mode 100755
index 0000000..7d2eb53
--- /dev/null
+++ b/scripts/machine-summary.py
@@ -0,0 +1,122 @@
+#! /usr/bin/env python3
+
+import os
+import sys
+import argparse
+import datetime
+
+import jinja2
+
+def get_template(name):
+ template_dir = os.path.dirname(os.path.abspath(__file__))
+ env = jinja2.Environment(
+ loader=jinja2.FileSystemLoader(template_dir),
+ autoescape=jinja2.select_autoescape(),
+ trim_blocks=True,
+ lstrip_blocks=True
+ )
+ def is_old(version, upstream):
+ if "+git" in version:
+ # strip +git and see if this is a post-release snapshot
+ version = version.replace("+git", "")
+ return version != upstream
+ env.tests["old"] = is_old
+
+ return env.get_template(f"machine-summary-{name}.jinja")
+
+def trim_pv(pv):
+ """
+ Strip anything after +git from the PV
+ """
+ return "".join(pv.partition("+git")[:2])
+
+def layer_path(layername, d):
+ """
+ Return the path to the specified layer, or None if the layer isn't present.
+ """
+ import re
+ bbpath = d.getVar("BBPATH").split(":")
+ pattern = d.getVar('BBFILE_PATTERN_' + layername)
+ for path in reversed(sorted(bbpath)):
+ if re.match(pattern, path + "/"):
+ return path
+ return None
+
+def harvest_data(machines, recipes):
+ import bb.tinfoil, bb.utils
+ with bb.tinfoil.Tinfoil() as tinfoil:
+ tinfoil.prepare(config_only=True)
+ corepath = layer_path("core", tinfoil.config_data)
+ sys.path.append(os.path.join(corepath, "lib"))
+ import oe.recipeutils
+ import oe.patch
+
+ # Queue of recipes that we're still looking for upstream releases for
+ to_check = list(recipes)
+
+ # Upstream releases
+ upstreams = {}
+ # Machines to recipes to versions
+ versions = {}
+
+ for machine in machines:
+ print(f"Gathering data for {machine}...")
+ os.environ["MACHINE"] = machine
+ with bb.tinfoil.Tinfoil() as tinfoil:
+ versions[machine] = {}
+
+ tinfoil.prepare(quiet=2)
+ for recipe in recipes:
+ try:
+ d = tinfoil.parse_recipe(recipe)
+ except bb.providers.NoProvider:
+ continue
+
+ if recipe in to_check:
+ try:
+ info = oe.recipeutils.get_recipe_upstream_version(d)
+ upstreams[recipe] = info["version"]
+ to_check.remove(recipe)
+ except (bb.providers.NoProvider, KeyError):
+ pass
+
+ details = versions[machine][recipe] = {}
+ details["recipe"] = d.getVar("PN")
+ details["version"] = trim_pv(d.getVar("PV"))
+ details["patched"] = bool(oe.patch.src_patches(d))
+
+ # Now backfill the upstream versions
+ for machine in versions:
+ for recipe in versions[machine]:
+ versions[machine][recipe]["upstream"] = upstreams[recipe]
+
+ return upstreams, versions
+
+# TODO can this be inferred from the list of recipes in the layer
+recipes = ("virtual/kernel",
+ "scp-firmware",
+ "trusted-firmware-a",
+ "trusted-firmware-m",
+ "edk2-firmware",
+ "u-boot",
+ "optee-os",
+ "armcompiler-native",
+ "gcc-aarch64-none-elf-native",
+ "gcc-arm-none-eabi-native")
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description="machine-summary")
+ parser.add_argument("machines", nargs="+", help="machine names", metavar="MACHINE")
+ parser.add_argument("-t", "--template", required=True)
+ parser.add_argument("-o", "--output", required=True, type=argparse.FileType('w', encoding='UTF-8'))
+ args = parser.parse_args()
+
+ template = get_template(args.template)
+
+ context = {}
+ # TODO: include git describe for meta-arm
+ context["timestamp"] = str(datetime.datetime.now().strftime("%c"))
+ context["recipes"] = sorted(recipes)
+ context["releases"], context["data"] = harvest_data(args.machines, recipes)
+
+ args.output.write(template.render(context))
--
2.25.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2021-08-12 9:50 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-12 9:49 [PATCH 1/3] ci/listmachines: add helper to list machines in a layer Ross Burton
2021-08-12 9:49 ` [PATCH 2/3] ci/check-machine-coverage: use listmachines.py Ross Burton
2021-08-12 9:49 ` [PATCH 3/3] scripts: add machine summary report tool Ross Burton
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).