fd11aa716c
redbear-ci / check (push) Has been cancelled
Unblocks plasma-workspace/plasma-desktop, which required 14 packages that had
no in-tree recipe. Sources are reproducible from each recipe's tar= + blake3;
the vendored source/ trees are deliberately not committed here (212M).
New recipes:
KF6 6.28.0 kf6-kholidays, kf6-krunner, kf6-kstatusnotifieritem,
kf6-kunitconversion
Plasma 6.7.2 knighttime, layer-shell-qt, libkscreen, libksysguard,
plasma-activities-stats, plasma5support, kscreenlocker
Qt 6.11.1 qtpositioning, qtspeech, qttools
libksysguard carries P0-redox-process-backend.patch: processes_local_p.cpp
dispatches on platform macros and had no __redox__ arm, so ProcessesLocal was
entirely undefined. Adds a real backend reading /scheme/proc/ps (pid, ppid,
real+effective ids, thread count, state) and /scheme/sys/mem, with kill() for
signals. Upstream's generic fallback is a pure stub and was not used. Absent
facilities (no setpriority/sched_setscheduler/ioprio on a microkernel) report
NotSupported rather than pretending.
Restored, no longer disabled:
- night colour: kcms/nighttime + kwin's nightlight plugin, now that
KNightTime/Qt6Positioning/KF6Holidays exist
- KIO FileWidgets (file dialog, places model), wrongly swept in with the
unportable kiod/kssld/kioworkers subdirs
- kf6-ktexteditor text-to-speech: removes a disguised stub that rewrote
speechEngine() to return nullptr and mangled call sites into invalid C++
- kwin KWIN_BUILD_SCREENLOCKER=ON (needs kscreenlocker; see below)
Toolchain and recipe fixes:
- redox-toolchain.cmake: append -lgcc. __extendhfsf2/__extendbfsf2 are
global in libgcc.a but hidden in libgcc_s.so (the Redox libgcc version map
stops at GCC_7.0.0 and never emits the GCC_12/13 nodes upstream exports),
and GCC omits -lgcc for -shared, so no C++23 shared library using
std::format<_Float16|bfloat16_t> could link.
- qtmultimedia: rewrite /usr/src/.../meta_types paths and stage metatypes,
so consumers using qt_internal_add_qml_module can configure.
- qtspeech: qtmultimedia is mandatory, not optional -- upstream return()s
with only a NOTICE without it, yielding a green build over an empty
package. Asserts its own output so that cannot recur.
- narrow Linux-only guards with AND NOT REDOX where the toolchain sets
CMAKE_SYSTEM_NAME=Linux purely to get UNIX=TRUE (kio LibMount,
libksysguard NL/Sensors, plasma-workspace NetworkManagerQt).
- drop REQUIRED components that are declared but referenced nowhere
(Location, QCoro6, Qt6 Test) -- verified by exhaustive grep.
- DESTDIR installs where KDE emits absolute KDE_INSTALL_FULL_* paths that
--prefix cannot re-root, which otherwise write into the build host.
Auth stack:
- pam-redbear: add PAM_MODULE_UNKNOWN (28), missing from both the header and
lib.rs; realign 30/31 to Linux-PAM's PAM_CONV_AGAIN/PAM_INCOMPLETE, which
previously held Red Bear-only names on standard values, so anything built
against stock PAM headers mis-decoded them.
- redbear-authd: support yescrypt ($y$ -- the default shadow format on
current Debian/Ubuntu/Fedora, previously an unexplained login failure),
bcrypt and md5-crypt. Plaintext shadow entries now require the
/etc/redbear/allow-plaintext-passwords sentinel and warn on every use,
instead of being compared silently. 19/19 host tests pass.
Build-system hardening:
- verify-tracked-sources.sh, wired into preflight: fails on deletion of any
tracked vendored source, and on modifications with no baseline entry.
local/sources/ had a dirty gate and version checks; local/recipes/*/source/
had none, which allowed an rm -rf to delete 7958 tracked files and a
pristine re-extract to silently overwrite committed fixes (kwin's
std::expected/vulkan-hpp and X11 gating, kio's Q_OS_REDOX resolver guards).
- validate-source-trees.py: resolve recipe.toml through the overlay symlink;
it reported false MISSING for symlinked recipes.
- test-sddm-virgl-qemu.sh: the null-proxy check used report(), which PASSES
on regex match -- so the known Qt6 Wayland null+8 fault would report PASS
when present. Added report_absent().
kscreenlocker builds only its cmake-level Wayland-only changes so far; the
C++ X11 removal (61 call sites) is not yet applied, so kwin's screenlocker
flag is blocked on it.
149 lines
5.3 KiB
Python
Executable File
149 lines
5.3 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Validate that all source trees required by a build config exist."""
|
|
|
|
import argparse
|
|
import sys
|
|
import tomllib
|
|
from pathlib import Path
|
|
|
|
PROJECT_ROOT = Path(__file__).resolve().parents[2]
|
|
META_PACKAGES = {"libgcc", "libstdcxx"}
|
|
|
|
|
|
def build_lookup():
|
|
lookup = {}
|
|
for root in (PROJECT_ROOT / "recipes", PROJECT_ROOT / "local/recipes"):
|
|
for recipe_toml in root.rglob("recipe.toml"):
|
|
parts = recipe_toml.parts
|
|
if "source" in parts or "target" in parts:
|
|
continue
|
|
package_name = recipe_toml.parent.name
|
|
if package_name not in lookup:
|
|
# Resolve through the overlay symlink. `recipes/<cat>/<name>` is
|
|
# frequently a symlink (whole-dir) or contains a symlinked
|
|
# recipe.toml pointing into `local/recipes/<cat>/<name>`, which is
|
|
# where the vendored `source/` tree actually lives. Recording the
|
|
# unresolved parent made the source lookup miss it and report a
|
|
# false MISSING (e.g. xwayland).
|
|
lookup[package_name] = recipe_toml.resolve().parent
|
|
return lookup
|
|
|
|
|
|
def resolve_config(config_path: Path, visited=None):
|
|
if visited is None:
|
|
visited = set()
|
|
config_path = config_path.resolve()
|
|
if config_path in visited:
|
|
return {}
|
|
visited.add(config_path)
|
|
with open(config_path, "rb") as config_file:
|
|
config = tomllib.load(config_file)
|
|
packages = dict(config.get("packages", {}))
|
|
for include in config.get("include", []):
|
|
include_path = config_path.parent / include
|
|
if include_path.exists():
|
|
included_packages = resolve_config(include_path, visited)
|
|
for package_name, package_value in packages.items():
|
|
included_packages[package_name] = package_value
|
|
packages = included_packages
|
|
return packages
|
|
|
|
|
|
def recipe_restore_path(recipe_dir: Path):
|
|
recipes_root = PROJECT_ROOT / "recipes"
|
|
try:
|
|
return recipe_dir.relative_to(recipes_root).as_posix()
|
|
except ValueError:
|
|
return None
|
|
|
|
|
|
def same_as_source_dir(recipe_dir: Path):
|
|
recipe_file = recipe_dir / "recipe.toml"
|
|
if not recipe_file.exists():
|
|
return None
|
|
with open(recipe_file, "rb") as handle:
|
|
recipe = tomllib.load(handle)
|
|
source = recipe.get("source")
|
|
if not isinstance(source, dict):
|
|
return None
|
|
same_as = source.get("same_as")
|
|
if not isinstance(same_as, str) or not same_as:
|
|
return None
|
|
return (recipe_dir / same_as).resolve() / "source"
|
|
|
|
|
|
def parse_args():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("config", nargs="?", default="redbear-full")
|
|
parser.add_argument("--extra-package", action="append", default=[])
|
|
parser.add_argument("--missing-paths-only", action="store_true")
|
|
parser.add_argument("--release", default="")
|
|
return parser.parse_args()
|
|
|
|
|
|
def main():
|
|
args = parse_args()
|
|
config_path = PROJECT_ROOT / "config" / f"{args.config}.toml"
|
|
if not config_path.exists():
|
|
print(f"Config not found: {config_path}", file=sys.stderr)
|
|
return 1
|
|
|
|
lookup = build_lookup()
|
|
packages = resolve_config(config_path)
|
|
requested_packages = dict(packages)
|
|
for package_name in args.extra_package:
|
|
requested_packages.setdefault(package_name, {})
|
|
|
|
missing_recipe_paths = []
|
|
missing_entries = []
|
|
present = 0
|
|
|
|
for package_name, package_conf in sorted(requested_packages.items()):
|
|
if str(package_conf) == "ignore" or package_name in META_PACKAGES:
|
|
continue
|
|
recipe_dir = lookup.get(package_name)
|
|
if recipe_dir is None:
|
|
missing_entries.append((package_name, None))
|
|
continue
|
|
source_dir = recipe_dir / "source"
|
|
if source_dir.is_dir() and any(source_dir.iterdir()):
|
|
present += 1
|
|
continue
|
|
alias_source_dir = same_as_source_dir(recipe_dir)
|
|
if alias_source_dir is not None and alias_source_dir.is_dir() and any(alias_source_dir.iterdir()):
|
|
present += 1
|
|
continue
|
|
missing_entries.append((package_name, recipe_dir))
|
|
restore_path = recipe_restore_path(recipe_dir)
|
|
if restore_path is not None:
|
|
missing_recipe_paths.append(restore_path)
|
|
|
|
if args.missing_paths_only:
|
|
seen = set()
|
|
for recipe_path in missing_recipe_paths:
|
|
if recipe_path not in seen:
|
|
print(recipe_path)
|
|
seen.add(recipe_path)
|
|
return 0 # Missing sources are non-fatal; they get fetched during build
|
|
|
|
print(f"=== Validating source trees for config: {args.config} ===")
|
|
for package_name, recipe_dir in missing_entries:
|
|
if recipe_dir is None:
|
|
print(f" NOT FOUND: {package_name}")
|
|
else:
|
|
print(f" MISSING: {recipe_dir.relative_to(PROJECT_ROOT)}")
|
|
|
|
total = present + len(missing_entries)
|
|
print(f"\n Total (config): {total}")
|
|
print(f" Present: {present}")
|
|
print(f" Missing: {len(missing_entries)}")
|
|
if missing_entries:
|
|
release = args.release or "<release>"
|
|
print(f"\nTo restore: ./local/scripts/restore-sources.sh --release={release}")
|
|
print("Source tree validation complete.")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|