meta-arm.lists.yoctoproject.org archive mirror
 help / color / mirror / Atom feed
* [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).