Files
2026-10-31 18:07:56 -03:00

139 lines
5.1 KiB
Python

# SPDX-License-Identifier: GPL-3.0-or-later
"""Remove generated package files and reset isolated build environments."""
import shutil
import subprocess
from pathlib import Path
import project as p
def remove(path):
if path.is_symlink() or path.is_file():
path.unlink()
elif path.exists():
shutil.rmtree(path)
def clean_apt_cache():
"""Remove cached APT downloads while retaining logs and build artifacts."""
cache = p.WORK / "apt-cache"
if cache.is_symlink():
raise ValueError("APT cache directory must not be a symlink")
remove(cache)
print("APT cache cleared")
def has_generated_files(module, accepted=False):
"""Report whether cleanup can remove any generated files for this project."""
entry = p.packages()[module]
recipe, version = p.recipe(module)
prepared = p.WORK / "prepared" / (module + ".json")
target = p.WORK / "sources" / (entry["source"] + "-" + version)
if prepared.exists() or target.exists() or target.is_symlink():
return True
for path in (p.WORK / "sources").glob(entry["source"] + "_*"):
if path.is_file() and not (".orig.tar." in path.name or ".orig-" in path.name):
return True
state = p.WORK / "state" / (module + ".json")
if state.exists():
if accepted:
return True
keep = set(p.read(state)["artifacts"])
else:
if (p.WORK / "input/modules" / (module + ".json")).exists():
return True
keep = set()
control = p.fields((recipe / "control").read_text())
names = {entry["source"], *(paragraph["Package"] for paragraph in control[1:])}
results = p.WORK / "results"
for name in names:
if any(
not path.name.endswith(".build") and path.name not in keep
for path in results.glob(name + "_*")
):
return True
if any(path.name not in keep for path in results.glob(name + "-dbgsym_*.deb")):
return True
return False
def clean(module, accepted=False):
entry = p.packages()[module]
recipe, version = p.recipe(module)
state_path = p.WORK / "state" / (module + ".json")
state = p.read(state_path) if state_path.exists() else None
results = p.WORK / "results"
if results.is_symlink():
raise ValueError("Results directory must not be a symlink")
artifacts = list(state["artifacts"]) if state else []
if any(Path(name).name != name for name in artifacts):
raise ValueError("Invalid artifact filename in build record: " + module)
if accepted and (p.WORK / "repository/conf/distributions").exists():
if not (p.WORK / "controller/etc/debian_version").exists():
raise ValueError(
"Run setup before removing packages from the local repository."
)
subprocess.run(
[
"sudo",
"bash",
str(p.ROOT / "tools/lib/controller-enter"),
"builder",
"reprepro",
"--basedir",
"/work/repository",
"removesrc",
p.read(p.ROOT / "config/release.json")["build_suite"],
entry["source"],
],
check=True,
)
prepared = p.WORK / "prepared" / (module + ".json")
targets = {p.WORK / "sources" / (entry["source"] + "-" + version)}
if prepared.exists():
relative = Path(p.read(prepared)["target"])
if (
relative.is_absolute()
or len(relative.parts) != 2
or relative.parts[0] != "sources"
):
raise ValueError("Invalid prepared source path: " + str(relative))
targets.add(p.WORK / relative)
source_root = p.WORK / "sources"
for target in sorted(targets):
if target.parent != source_root or source_root.is_symlink():
raise ValueError("Invalid source directory: " + str(target))
remove(target)
remove(prepared)
for path in source_root.glob(entry["source"] + "_*"):
if path.is_file() and not (".orig.tar." in path.name or ".orig-" in path.name):
remove(path)
keep = set() if accepted else set(artifacts)
control = p.fields((recipe / "control").read_text())
names = {entry["source"], *(paragraph["Package"] for paragraph in control[1:])}
for name in sorted(names):
for path in results.glob(name + "_*"):
if path.name.endswith(".build") or path.name in keep:
continue
remove(path)
for path in results.glob(name + "-dbgsym_*.deb"):
if path.name not in keep:
remove(path)
if accepted:
for name in artifacts:
if not name.endswith(".build"):
remove(results / name)
remove(state_path)
remove(p.WORK / "records/package-library-split-audit.json")
if accepted or not state_path.exists():
remove(p.WORK / "input/modules" / (module + ".json"))
if accepted:
print(
module + ": generated sources, accepted artifacts and build records cleaned"
)
else:
print(module + ": generated sources and unaccepted results cleaned")