SonicDE hard fork and upgrade to 6.7
This commit is contained in:
parent
49c8c3d2ce
commit
ca95bace9a
167 changed files with 16629 additions and 419 deletions
120
ci/generate-build-order.py
Executable file
120
ci/generate-build-order.py
Executable file
|
|
@ -0,0 +1,120 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Recompute build-order.txt tiers from the BuildRequires of every spec.
|
||||
|
||||
The tiers generated from the SonicDE builder dependency graph only describe
|
||||
source-level dependencies; RPM build dependencies are wider (devel subpackages,
|
||||
cmake config files, pkgconfig files). This derives the tiers from the specs
|
||||
themselves so a tier only needs packages from earlier tiers.
|
||||
"""
|
||||
import glob
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
|
||||
REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
specs = sorted(glob.glob(os.path.join(REPO, "*", "*.spec")))
|
||||
specs = [s for s in specs if os.path.basename(s)[:-5] == os.path.basename(os.path.dirname(s))]
|
||||
|
||||
provides = {} # capability -> package dir name
|
||||
brs = defaultdict(set)
|
||||
|
||||
|
||||
def parse(spec):
|
||||
pkg = os.path.basename(spec)[:-5]
|
||||
out = subprocess.run(["rpmspec", "-P", spec], capture_output=True, text=True).stdout
|
||||
if not out:
|
||||
out = open(spec, errors="replace").read()
|
||||
names = {pkg}
|
||||
in_files = False
|
||||
for line in out.splitlines():
|
||||
s = line.strip()
|
||||
m = re.match(r"%package\s+(?:-n\s+(\S+)|(\S+))", s)
|
||||
if m:
|
||||
names.add(m.group(1) or f"{pkg}-{m.group(2)}")
|
||||
continue
|
||||
if s.startswith("%files"):
|
||||
in_files = True
|
||||
elif s.startswith("%") and re.match(r"%(prep|build|install|conf|check|changelog|description|post|pre)", s):
|
||||
in_files = s.startswith("%files")
|
||||
m = re.match(r"(Provides|BuildRequires)\s*:\s*(.+)", s)
|
||||
if m:
|
||||
for dep in re.split(r"\s+(?=[A-Za-z_%(/])", m.group(2).strip()):
|
||||
cap = dep.split()[0].replace("%{?_isa}", "").strip()
|
||||
if not cap or cap.startswith(("%", "(")):
|
||||
continue
|
||||
if m.group(1) == "Provides":
|
||||
names.add(cap)
|
||||
else:
|
||||
brs[pkg].add(cap)
|
||||
if in_files:
|
||||
for cm in re.findall(r"/cmake/([A-Za-z0-9_.+-]+)/?", s):
|
||||
names.add(f"cmake({cm})")
|
||||
for pc in re.findall(r"/([A-Za-z0-9_.+-]+)\.pc\b", s):
|
||||
names.add(f"pkgconfig({pc})")
|
||||
for n in names:
|
||||
provides.setdefault(n, pkg)
|
||||
return pkg
|
||||
|
||||
|
||||
pkgs = [parse(s) for s in specs]
|
||||
|
||||
edges = defaultdict(set)
|
||||
for pkg in pkgs:
|
||||
for cap in brs[pkg]:
|
||||
owner = provides.get(cap)
|
||||
if owner and owner != pkg:
|
||||
edges[pkg].add(owner)
|
||||
|
||||
# longest-path tier assignment, ignoring back edges of cycles
|
||||
tier = {}
|
||||
state = {}
|
||||
|
||||
|
||||
def depth(pkg, stack=()):
|
||||
if pkg in tier:
|
||||
return tier[pkg]
|
||||
if pkg in stack:
|
||||
return 0
|
||||
d = 0
|
||||
for dep in edges[pkg]:
|
||||
d = max(d, depth(dep, stack + (pkg,)) + 1)
|
||||
tier[pkg] = d
|
||||
return d
|
||||
|
||||
|
||||
sys.setrecursionlimit(10000)
|
||||
for pkg in pkgs:
|
||||
depth(pkg)
|
||||
|
||||
cycles = []
|
||||
for pkg in pkgs:
|
||||
for dep in edges[pkg]:
|
||||
if tier[dep] >= tier[pkg]:
|
||||
cycles.append((pkg, dep))
|
||||
|
||||
groups = defaultdict(list)
|
||||
for pkg in pkgs:
|
||||
groups[tier[pkg]].append(pkg)
|
||||
|
||||
lines = [
|
||||
"# Build order for the SonicDE packages, derived from the BuildRequires of",
|
||||
"# every spec in this repository (see ci/generate-build-order.py).",
|
||||
"#",
|
||||
"# Packages inside one tier are independent and can be built in parallel;",
|
||||
"# the tiers themselves must be built in order.",
|
||||
"",
|
||||
]
|
||||
for i, t in enumerate(sorted(groups), start=1):
|
||||
lines.append(f"[tier{i}]")
|
||||
lines += sorted(groups[t])
|
||||
lines.append("")
|
||||
|
||||
open(os.path.join(REPO, "build-order.txt"), "w").write("\n".join(lines).rstrip() + "\n")
|
||||
print("tiers:", len(groups), "packages:", len(pkgs))
|
||||
if cycles:
|
||||
print("dependency cycles (built with the earlier tier's package from the repo):")
|
||||
for a, b in sorted(set(cycles)):
|
||||
print(f" {a} <- {b}")
|
||||
Loading…
Add table
Add a link
Reference in a new issue