diff --git a/pmb/commands/log.py b/pmb/commands/log.py index ab196ec0..fd806f35 100644 --- a/pmb/commands/log.py +++ b/pmb/commands/log.py @@ -7,6 +7,7 @@ from pmb import commands from pmb.types import PathString from pmb.helpers import run from pmb.core.context import get_context +import pmb.config class Log(commands.Command): clear_log: bool @@ -18,7 +19,7 @@ class Log(commands.Command): def run(self): context = get_context() - log_testsuite = context.config.work / "log_testsuite.txt" + log_testsuite = pmb.config.pmb_src / ".pytest_tmp/log_testsuite.txt" if self.clear_log: run.user(["truncate", "-s", "0", context.log]) diff --git a/pmb/config/file.py b/pmb/config/file.py index 3e2024da..12a3de7b 100644 --- a/pmb/config/file.py +++ b/pmb/config/file.py @@ -46,7 +46,11 @@ def load(path: Path) -> Config: # Yeah this really sucks and there isn't a better way to do it without external # libraries elif isinstance(getattr(Config, key), List) and isinstance(getattr(Config, key)[0], PosixPath): - setattr(config, key, [Path(p.strip()) for p in cfg["pmbootstrap"][key].split(",")]) + value = cfg["pmbootstrap"][key] + if not value: + setattr(config, key, value) + else: + setattr(config, key, [Path(p) for p in value.split(",")]) elif isinstance(getattr(Config, key), bool): setattr(config, key, cfg["pmbootstrap"][key].lower() == "true") elif key in cfg["pmbootstrap"]: diff --git a/pmb/config/init.py b/pmb/config/init.py index 00681270..5084f482 100644 --- a/pmb/config/init.py +++ b/pmb/config/init.py @@ -663,7 +663,7 @@ def frontend(args: PmbArgs): # Choose release channel, possibly switch pmaports branch channel = ask_for_channel(config) - pmb.config.pmaports.switch_to_channel_branch(args, channel) + pmb.config.pmaports.switch_to_channel_branch(channel) # FIXME: ??? config.is_default_channel = False diff --git a/pmb/config/pmaports.py b/pmb/config/pmaports.py index a0d9b7e2..39bacb6b 100644 --- a/pmb/config/pmaports.py +++ b/pmb/config/pmaports.py @@ -174,7 +174,7 @@ def init(): read_config() -def switch_to_channel_branch(args: PmbArgs, channel_new): +def switch_to_channel_branch(channel_new): """Checkout the channel's branch in pmaports.git. :channel_new: channel name (e.g. "edge", "v21.03") @@ -198,7 +198,7 @@ def switch_to_channel_branch(args: PmbArgs, channel_new): f" '{channel_new}'...") # Make sure we don't have mounts related to the old channel - pmb.chroot.shutdown(args) + pmb.chroot.shutdown() # Attempt to switch branch (git gives a nice error message, mentioning # which files need to be committed/stashed, so just pass it through) diff --git a/pmb/config/test_config_serde.py b/pmb/config/test_config_serde.py index a447aebb..36a95f56 100644 --- a/pmb/config/test_config_serde.py +++ b/pmb/config/test_config_serde.py @@ -92,3 +92,4 @@ def test_migrate_2_to_3(config_file_2_3_x, tmp_path, monkeypatch): # Check that save was called (which happens on a config migration) assert did_migrate +# FIXME: add save tests and better type checks diff --git a/pmb/conftest.py b/pmb/conftest.py index 077bb516..4fadc398 100644 --- a/pmb/conftest.py +++ b/pmb/conftest.py @@ -4,21 +4,32 @@ import pytest import shutil import pmb.core +from pmb.core.context import get_context from pmb.types import PmbArgs from pmb.helpers.args import init as init_args _testdir = Path(__file__).parent / "data/tests" @pytest.fixture -def config_file(tmp_path_factory): +def config_file(tmp_path_factory, request): """Fixture to create a temporary pmbootstrap.cfg file.""" tmp_path = tmp_path_factory.mktemp("pmbootstrap") + + flavour = "default" + if hasattr(request, "param") and request.param: + flavour = request.param + out_file = tmp_path / "pmbootstrap.cfg" workdir = tmp_path / "work" workdir.mkdir() + + configs = {"default": f"aports = {workdir / 'cache_git' / 'pmaports'}", + "no-repos": "aports = "} file = _testdir / "pmbootstrap.cfg" - contents = open(file).read().format(workdir) + print(f"config_file: {out_file}") + cfg = configs[flavour] + contents = open(file).read().format(workdir, cfg) open(out_file, "w").write(contents) return out_file @@ -53,11 +64,14 @@ def mock_devices_find_path(device_package, monkeypatch): @pytest.fixture(autouse=True) -def setup_logging(tmp_path: Path): +def logfile(tmp_path_factory): """Setup logging for all tests.""" - import logging - logfile = tmp_path / "test.log" - logging.basicConfig(level=logging.DEBUG, force=True, filename=logfile) + from pmb.helpers import logging + tmp_path = tmp_path_factory.getbasetemp() + logfile = tmp_path / "log_testsuite.txt" + logging.init(logfile, verbose=True) + + return logfile @pytest.fixture(autouse=True) @@ -92,7 +106,7 @@ def mock_context(monkeypatch): # FIXME: get_context() at runtime somehow doesn't return the # custom context we set up here. @pytest.fixture -def pmb_args(config_file, mock_context): +def pmb_args(config_file, mock_context, logfile): """This is (still) a hack, since a bunch of the codebase still expects some global state to be initialised. We do that here.""" @@ -102,15 +116,18 @@ def pmb_args(config_file, mock_context): args.timeout = 900 args.details_to_stdout = False args.quiet = False - args.verbose = False + args.verbose = True args.offline = False args.action = "init" args.cross = False - args.log = Path() + args.log = logfile print("init_args") init_args(args) + # Sanity check + assert ".pytest_tmp" in get_context().config.work.parts + @pytest.fixture def foreign_arch(): """Fixture to return the foreign arch.""" @@ -120,3 +137,22 @@ def foreign_arch(): return Arch.x86_64 + +@pytest.fixture +def pmaports(pmb_args, monkeypatch): + """Fixture to clone pmaports.""" + + from pmb.core import Config + from pmb.core.context import get_context + + config = get_context().config + + with monkeypatch.context() as m: + # Speed things up by cloning from the local checkout if it exists. + if Config.aports[0].exists(): + m.setitem(pmb.config.git_repos, "pmaports", Config.aports) + + pmb.helpers.git.clone("pmaports") + + assert pmb.helpers.run.user(["git", "checkout", "master"], + working_dir=config.aports[0]) == 0 diff --git a/pmb/core/test_pkgrepo.py b/pmb/core/test_pkgrepo.py new file mode 100644 index 00000000..a71a071f --- /dev/null +++ b/pmb/core/test_pkgrepo.py @@ -0,0 +1,40 @@ +import pytest + +import pmb.helpers.git +import pmb.helpers.run +from pmb.core.pkgrepo import pkgrepo_paths, pkgrepo_default_path + + +@pytest.mark.parametrize("config_file", ["no-repos"], indirect=True) +def test_pkgrepo_paths_no_repos(pmb_args): + """Test pkgrepo_paths() with no repositories. Should raise a RuntimeError.""" + with pytest.raises(RuntimeError): + paths = pkgrepo_paths() + print(paths) + +def test_pkgrepo_pmaports(pmaports, monkeypatch): + """Test pkgrepo_paths() with pmaports repository and systemd extra repo""" + + # Disable results caching + pkgrepo_paths.cache_disable() + + paths = pkgrepo_paths() + print(f"[master] pkgrepo_paths: {paths}") + assert len(paths) == 1 + assert "pmaports" in paths[0].name + + default_path = pkgrepo_default_path() + + assert default_path.name == "pmaports" + + # Test extra-repos + assert pmb.helpers.run.user(["git", "checkout", "master_staging_systemd"], + working_dir=default_path) == 0 + + paths = pkgrepo_paths() + assert len(paths) == 2 + + # systemd is the first path, since we want packages there to take priority + assert paths[0].name == "systemd" + # but pmaports is the default rep, since it has channels.cfg/pmaports.cfg + assert pkgrepo_default_path().name == "pmaports" diff --git a/pmb/data/tests/pmbootstrap.cfg b/pmb/data/tests/pmbootstrap.cfg index 9f484fed..074ad34f 100644 --- a/pmb/data/tests/pmbootstrap.cfg +++ b/pmb/data/tests/pmbootstrap.cfg @@ -1,4 +1,5 @@ [pmbootstrap] +{1} build_default_device_arch = True ccache_size = 5G device = qemu-amd64 diff --git a/pmb/helpers/git.py b/pmb/helpers/git.py index 99230734..02b23d6b 100644 --- a/pmb/helpers/git.py +++ b/pmb/helpers/git.py @@ -48,7 +48,7 @@ def clone(name_repo: str): command += [url, path] # Create parent dir and clone - logging.info("Clone git repository: " + url) + logging.info(f"Clone git repository: {url}") (get_context().config.work / "cache_git").mkdir(exist_ok=True) pmb.helpers.run.user(command, output="stdout")