mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-11-12 11:31:08 +00:00
Select the explicitly configured Android render node for nested KWin 6.8, apply OpenGL settings before Plasma starts, and pin the original signed Mesa 26.2.4 package that passed Thor rendering. Remove build-directory runtime search paths and fail closed on ELF inspection errors. Native ARM64 build passed. Thor validated a visible nested Wayland terminal, active OpenGL ES/Zink on Turnip, 1280x720 output, and keyboard input. Mesa pin regression tests, launcher and ELF failure controls, shell syntax, and human authorship checks passed. Published desktop pin remains r2; full latest-head CI is pending and maintainer authorized this merge after device validation.
156 lines
5.5 KiB
Python
Executable File
156 lines
5.5 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""The packages the KDE desktop package ships: the dependency closure of the seeds over Arch Linux
|
|
ARM's extracted repository databases, minus what the runtime already has at a version that serves.
|
|
|
|
closure.py <db dir with x_core, x_extra, x_alarm> <runtime-packages.txt> <seeds.txt>
|
|
|
|
Prints one "repo/filename sha256" per package to ship (the sha256 the repository database gives).
|
|
"""
|
|
import collections
|
|
import os
|
|
import re
|
|
import sys
|
|
|
|
REPOS = ("core", "extra", "alarm")
|
|
|
|
|
|
def vercmp_part(a, b):
|
|
if a == b:
|
|
return 0
|
|
sa = re.findall(r"\d+|[a-zA-Z]+", a)
|
|
sb = re.findall(r"\d+|[a-zA-Z]+", b)
|
|
for x, y in zip(sa, sb):
|
|
if x.isdigit() and y.isdigit():
|
|
x, y = int(x), int(y)
|
|
if x != y:
|
|
return 1 if x > y else -1
|
|
elif x.isdigit():
|
|
return 1
|
|
elif y.isdigit():
|
|
return -1
|
|
elif x != y:
|
|
return 1 if x > y else -1
|
|
if len(sa) == len(sb):
|
|
return 0
|
|
return 1 if len(sa) > len(sb) else -1
|
|
|
|
|
|
def vercmp(a, b):
|
|
def split(v):
|
|
epoch, _, rest = v.rpartition(":") if ":" in v else ("0", "", v)
|
|
ver, _, rel = rest.partition("-")
|
|
return int(epoch or 0), ver, rel
|
|
ea, va, ra = split(a)
|
|
eb, vb, rb = split(b)
|
|
if ea != eb:
|
|
return 1 if ea > eb else -1
|
|
c = vercmp_part(va, vb)
|
|
if c or not ra or not rb:
|
|
return c
|
|
return vercmp_part(ra, rb)
|
|
|
|
|
|
def parse_dep(d):
|
|
m = re.match(r"^([^<>=]+)(>=|<=|=|>|<)?(.*)$", d)
|
|
return m.group(1), m.group(2), m.group(3)
|
|
|
|
|
|
def satisfies(version, op, want):
|
|
if not op:
|
|
return True
|
|
c = vercmp(version, want)
|
|
return {"=": c == 0, ">=": c >= 0, "<=": c <= 0, ">": c > 0, "<": c < 0}[op]
|
|
|
|
|
|
def main():
|
|
dbdir, runtime_file, seeds_file = sys.argv[1:4]
|
|
runtime = {}
|
|
for line in open(runtime_file):
|
|
parts = line.split()
|
|
if len(parts) == 2:
|
|
runtime[parts[0]] = parts[1]
|
|
seeds = [l.strip() for l in open(seeds_file) if l.strip() and not l.lstrip().startswith("#")]
|
|
|
|
pkgs, providers = {}, collections.defaultdict(list)
|
|
pins = os.path.join(os.path.dirname(__file__), "pins")
|
|
sources = [("extra", pins)]
|
|
sources.extend((repo, os.path.join(dbdir, "x_" + repo)) for repo in REPOS)
|
|
for repo, root in sources:
|
|
if not os.path.isdir(root):
|
|
continue
|
|
for entry in sorted(os.listdir(root)):
|
|
fields, key = {}, None
|
|
for fname in ("desc", "depends"):
|
|
path = os.path.join(root, entry, fname)
|
|
if not os.path.exists(path):
|
|
continue
|
|
for line in open(path, encoding="utf-8", errors="replace"):
|
|
line = line.rstrip("\n")
|
|
if line.startswith("%") and line.endswith("%"):
|
|
key = line.strip("%")
|
|
fields[key] = []
|
|
elif line == "":
|
|
key = None
|
|
elif key:
|
|
fields[key].append(line)
|
|
name = fields.get("NAME", [None])[0]
|
|
if not name or name in pkgs:
|
|
continue
|
|
if root == pins:
|
|
runtime.pop(name, None)
|
|
provides = [parse_dep(p) for p in fields.get("PROVIDES", [])]
|
|
pkgs[name] = {"repo": repo, "file": fields["FILENAME"][0], "version": fields["VERSION"][0],
|
|
"sha256": fields.get("SHA256SUM", [""])[0],
|
|
"depends": fields.get("DEPENDS", []), "provides": provides}
|
|
providers[name].append((name, pkgs[name]["version"]))
|
|
for pname, _, pver in provides:
|
|
providers[pname].append((name, pver or pkgs[name]["version"]))
|
|
|
|
def resolve(dep):
|
|
"""The package to take for a dependency string, and whether the runtime's copy serves."""
|
|
name, op, want = parse_dep(dep)
|
|
if name in runtime and satisfies(runtime[name], op, want):
|
|
return name, True
|
|
candidates = providers.get(name, [])
|
|
for real, _ in candidates:
|
|
if real in runtime:
|
|
if not op or runtime[real] == pkgs[real]["version"]:
|
|
return real, True
|
|
if satisfies_provider(real, name, op, want):
|
|
return real, False
|
|
for real, pver in candidates:
|
|
if satisfies(pver, op, want):
|
|
return real, False
|
|
return None, False
|
|
|
|
def satisfies_provider(real, name, op, want):
|
|
if real == name:
|
|
return satisfies(pkgs[real]["version"], op, want)
|
|
return any(p == name and satisfies(v or pkgs[real]["version"], op, want) for p, _, v in pkgs[real]["provides"])
|
|
|
|
ship, seen, missing = [], set(), []
|
|
queue = list(seeds)
|
|
while queue:
|
|
dep = queue.pop()
|
|
real, served = resolve(dep)
|
|
if real is None:
|
|
missing.append(dep)
|
|
continue
|
|
if served or real in seen:
|
|
continue
|
|
seen.add(real)
|
|
ship.append(real)
|
|
queue.extend(pkgs[real]["depends"])
|
|
if missing:
|
|
sys.exit("unresolved: " + " ".join(sorted(set(missing))))
|
|
upgraded = sorted(n for n in ship if n in runtime)
|
|
if upgraded:
|
|
print("replacing runtime packages: " + " ".join(f"{n} {runtime[n]} -> {pkgs[n]['version']}" for n in upgraded),
|
|
file=sys.stderr)
|
|
for name in sorted(ship):
|
|
print(pkgs[name]["repo"] + "/" + pkgs[name]["file"], pkgs[name]["sha256"])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|