#!/usr/bin/env python3 import json import pathlib import argparse import subprocess import tempfile import sys # Given a git repository and a base to search for layers (either a layer # directly, or a directory containing layers), run the patchscript and update # the specified JSON file. args = argparse.ArgumentParser(description="Update Patch Metrics") args.add_argument("-j", "--json", required=True, type=pathlib.Path, help="update specified JSON file") args.add_argument("-s", "--patchscript", required=True, type=pathlib.Path, help="patchreview script to run") args.add_argument("-r", "--repo", required=True, type=pathlib.Path, help="repository to use (e.g. path/to/poky)") args.add_argument("-l", "--layer", type=pathlib.Path, help="layer/repository to scan") args = args.parse_args() if not args.repo.is_dir(): print(f"{args.repo} is not a directory") sys.exit(1) if not args.layer.is_dir(): print(f"{args.layer} is not a directory") sys.exit(1) if not args.patchscript.is_file(): print(f"{args.patchscript} is not a file") print("Running patchmetrics-update") if "meta-openembedded" in args.layer.name: # 2023-01-01, arbitarily chosen epoch = "1672531200" else: # 2011-04-25, Yocto 1.0 release. epoch = "1301074853" with tempfile.TemporaryDirectory(prefix="patchmetrics-") as tempname: tempdir = pathlib.Path(tempname) layerdir = tempdir / args.layer.relative_to(args.repo) # Create a temporary clone of the repository as we'll be checking out different revisions print(f"Making a temporary clone of {args.repo} to {tempdir}") subprocess.check_call(["git", "clone", "--quiet", args.repo, tempdir]) # Identify what revisions need to be analysed. If we reverse the list, keep # order, and remove in-place, then iterating through a large number of # commits is faster. repo_revisions = subprocess.check_output(["git", "rev-list", "--reverse", "--since", epoch, "origin/master"], universal_newlines=True, cwd=tempdir).strip().split() revision_count = len(repo_revisions) if args.json.exists(): with open(args.json) as f: data = json.load(f) seen = set() for i in data: try: repo_revisions.remove(i["commit"]) except ValueError: pass new_count = len(repo_revisions) print("Found %s, need to scan %d revisions:\n%s" % (revision_count - new_count, new_count, str(repo_revisions))) # Run the patchreview script for every revision for rev in repo_revisions: print("Processing %s" % rev) subprocess.check_call(["git", "checkout", "--detach", rev], cwd=tempdir) subprocess.check_call([args.patchscript, "--json", args.json, layerdir]) print("Finished patchmetrics-update")