Skip to content

Commit

Permalink
Experimental --scrub-all-chroots option
Browse files Browse the repository at this point in the history
  • Loading branch information
praiskup committed Sep 6, 2024
1 parent 78592b7 commit e45c00a
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 15 deletions.
17 changes: 14 additions & 3 deletions mock/py/mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
from mockbuild.state import State
from mockbuild.trace_decorator import traceLog
import mockbuild.uid
from mockbuild.scrub_all import scrub_all_chroots

signal_names = {1: "SIGHUP",
13: "SIGPIPE",
Expand Down Expand Up @@ -150,6 +151,13 @@ def command_parse():
metavar=scrub_metavar,
help="completely remove the specified chroot "
"or cache dir or all of the chroot and cache")
parser.add_option(
"--scrub-all-chroots", action="store_const", dest="mode",
const="scrub-all-chroots", help=(
"[EXPERIMENTAL] run --scrub=all for all previously used "
"chroots (all -r/--root possibilities, also check the "
"--list-chroots optoin) and previously used unique "
"extensions (--uniqueext)."))
parser.add_option("--init", action="store_const", const="init", dest="mode",
help="initialize the chroot, do not build anything")
parser.add_option("--installdeps", action="store_const", const="installdeps",
Expand Down Expand Up @@ -586,9 +594,9 @@ def do_debugconfig(config_opts, expand=False):


@traceLog()
def do_listchroots(config_opts, uidManager):
def do_listchroots(config_path, uidManager):
uidManager.run_in_subprocess_without_privileges(
config.list_configs, config_opts,
config.list_configs, config_path,
)


Expand Down Expand Up @@ -668,6 +676,9 @@ def main():
if options.printrootpath or options.list_snapshots:
options.verbose = 0

if options.mode == "scrub-all-chroots":
return scrub_all_chroots()

# config path -- can be overridden on cmdline
config_path = MOCKCONFDIR
if options.configdir:
Expand Down Expand Up @@ -980,7 +991,7 @@ def run_command(options, args, config_opts, commands, buildroot):
do_debugconfig(config_opts, True)

elif options.mode == 'listchroots':
do_listchroots(config_opts, buildroot.uid_manager)
do_listchroots(config_opts["config_path"], buildroot.uid_manager)

elif options.mode == 'orphanskill':
util.orphansKill(buildroot.make_chroot_path())
Expand Down
50 changes: 38 additions & 12 deletions mock/py/mockbuild/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -797,40 +797,66 @@ def parse_config_filename(config_filename):
basename_without_ext = os.path.splitext(basename)[0]
return (basename, dirname, basename_without_ext)

def get_global_configs(config_opts):

def get_global_configs(config_path):
""" Return filenames of global configs of chroots"""
result = []
for config_filename in glob("{}/*.cfg".format(config_opts['config_path'])):
for config_filename in glob(f"{config_path}/*.cfg"):
if config_filename in ["/etc/mock/chroot-aliases.cfg", "/etc/mock/site-defaults.cfg"]:
continue
result.append(config_filename)
return result


def get_user_config_files(config_opts):
def get_user_config_files():
""" Return filenames of user configs of chroots """
uid = os.getuid()
custom_path = os.path.join(os.path.expanduser('~' + pwd.getpwuid(uid)[0]), '.config/mock/*.cfg')
result = glob(custom_path)
return result


def traverse_chroot_configs(config_path=MOCKCONFDIR,
system_configs_traversed_cb=None,
include_eol=False):
"""
Traverse the configuration directories, starting from the system-wide
directories, then going through $HOME/.mock/, and yield the (config_path,
config_filename, eol=True|False) 3-aries. Config_path is just passed to
callee unchanged!
"""
for config_filename in sorted(get_global_configs(config_path)):
yield config_path, config_filename, False

if include_eol:
for config_filename in sorted(get_global_configs(
os.path.join(config_path, "eol"))):
yield config_path, config_filename, True

if system_configs_traversed_cb:
system_configs_traversed_cb()

user_config_files = get_user_config_files()
if user_config_files:
# ~/.config/mock/CHROOTNAME.cfg
for config_filename in sorted(user_config_files):
yield config_path, config_filename, False


@traceLog()
def list_configs(config_opts):
def list_configs(config_path):
log = logging.getLogger()
log.disabled = True
# array to save config paths
print("{} {}".format("config name".ljust(34), "description"))
print("Global configs:")
for config_filename in sorted(get_global_configs(config_opts)):
print_description(config_opts['config_path'], config_filename)
user_config_files = get_user_config_files(config_opts)
if user_config_files:

def _print_custom():
print("Custom configs:")
# ~/.config/mock/CHROOTNAME.cfg
for config_filename in sorted(user_config_files):
print_description(config_opts['config_path'], config_filename)
log.disabled = False

for cp, fn, _ in traverse_chroot_configs(config_path, _print_custom):
print_description(cp, fn)
log.disabled = False


@traceLog()
Expand Down
110 changes: 110 additions & 0 deletions mock/py/mockbuild/scrub_all.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
"""
Logic for observing /var/lib/mock and /var/cache/mock, and try to cleanup as
much as possible sub-directories there.
"""


import os
from glob import glob
import subprocess
from mockbuild.constants import MOCKCONFDIR
from mockbuild.config import traverse_chroot_configs


def _do_scrub(configs, weird, chroot, suffix=None):
if suffix and chroot + "-" + suffix in weird:
print(f"skipping weird scrub: {chroot} {suffix}")
return

base_cmd = ["mock", "--scrub=all", "-r"]
cmd = base_cmd + ["eol/" + chroot if configs[chroot] == "eol" else chroot]
if suffix is not None:
cmd += ["--uniqueext", suffix]
subprocess.call(cmd)


def scrub_all_chroots():
"""
Traverse the important directories, and try to clean them up via
`--scrub=all` logic.
"""

configs = {}
scrub = set()
scrub_bootstrap = set()
scrub_uniqueext = set()
scrub_uniqueext_bootstrap = set()
scrub_weird = set()
guessing_suffix = {}

for item in glob("/etc/mock/*.cfg"):
configs[os.path.basename(item)[:-4]] = "normal"
for item in glob("/etc/mock/eol/*.cfg"):
configs[os.path.basename(item)[:-4]] = "eol"

configs = {os.path.basename(f)[:-4]: ("eol" if eol else "normal")
for _, f, eol in traverse_chroot_configs(MOCKCONFDIR,
include_eol=True)}

for directory in glob("/var/lib/mock/*") + glob("/var/cache/mock/*"):
if not os.path.isdir(directory):
continue

directory = os.path.basename(directory)

if directory in configs:
scrub.add(directory)
continue

if directory.endswith("-bootstrap"):
directory_no_bootstrap = directory[:-10]
if directory_no_bootstrap in configs:
scrub_bootstrap.add(directory_no_bootstrap)
continue

guessing_suffix[directory] = None

for config, _ in configs.items():
for directory in list(guessing_suffix.keys()):
if guessing_suffix[directory]:
# already found the cleaning thing
continue

if directory.startswith(config):

suffix = directory[len(config) + 1:]
if suffix.endswith("-bootstrap"):
# See this:
# 1. alma+epel-8-x86_64-php-bootstrap
# 2. alma+epel-8-x86_64-bootstrap-php
# The 1. is weird, and we miss the corresponding
# configuration. The second could be a "php" uniqueext.
weird_chroot = directory[:-10]
scrub_weird.add(weird_chroot)
continue

start = "bootstrap-"
if suffix.startswith(start):
suffix = suffix[len(start):]
scrub_uniqueext_bootstrap.add((config, suffix))
else:
scrub_uniqueext.add((config, suffix))

guessing_suffix[directory] = "uniqueext"

for sc, suffix in scrub_uniqueext_bootstrap - scrub_uniqueext:
_do_scrub(configs, scrub_weird, sc, suffix)

for sc, suffix in scrub_uniqueext:
_do_scrub(configs, scrub_weird, sc, suffix)

for only_bootstrap in scrub_bootstrap - scrub:
_do_scrub(configs, scrub_weird, only_bootstrap)

for sc in scrub:
_do_scrub(configs, scrub_weird, sc)

for directory, found in guessing_suffix.items():
if found:
continue
print(f"Unknown directory: {directory}")

0 comments on commit e45c00a

Please sign in to comment.