# SPDX-FileCopyrightText: 2023 Aurélien Gâteau # # SPDX-License-Identifier: GPL-3.0-or-later import os import platform import shlex import shutil import subprocess from pathlib import Path from tempfile import TemporaryDirectory import pytest from file_utils import rm_rf ROOT_DIR = Path(__file__).parent.parent.absolute() IS_WINDOWS = platform.system() == "Windows" # On GitHub Windows runner one gets an error message from WSL saying no # distributions are installed when running `bash` as is. Make it possible to # provide the full path to the bash binary to avoid this. BASH_CMD = os.environ.get("BASH_CMD", "bash") def _run(*args, check=True, **kwargs): """Wrapper for subprocess.run() to run a command and by default check the result but in case of failure, calls pytest.fail() instead of raising an exception. """ proc = subprocess.run( *args, capture_output=True, text=True, **kwargs ) if check and proc.returncode != 0: pytest.fail(f"""Command {args} failed with exit code {proc.returncode} STDOUT: {proc.stdout} STDERR: {proc.stderr} """) return proc def run_clyde(*args, check=True): """Run a Clyde command""" cmd = shlex.join(["clyde", *args]) return run_in_clyde_home(cmd, check=check) def run_in_clyde_home(cmd: str, check=True): """Run a command inside the Clyde home""" CLYDE_HOME = os.environ["CLYDE_HOME"] script = f". scripts/activate.sh ; {cmd}" cmd = [BASH_CMD, "-c", script] # Run the command directly in CLYDE_HOME. This avoids having to deal with # cygpath on Windows to get the path to the activate.sh script. return _run(cmd, check=check, cwd=str(CLYDE_HOME)) def get_bin_path(bin_name): """Returns the path to a binary inside Clyde home. Does not check if the binary exists.""" if IS_WINDOWS: bin_name += ".exe" return Path(os.environ["CLYDE_HOME"]) / "inst" / "bin" / bin_name def _build_clyde() -> Path: """Builds Clyde, returns the path to its binary""" cmd = ["cargo", "build", "-r"] _run(cmd, cwd=str(ROOT_DIR)) exe_name = "clyde.exe" if IS_WINDOWS else "clyde" path = ROOT_DIR / "target" / "release" / exe_name assert path.exists() return path @pytest.fixture(scope="session") def _setup_clyde_home(): """Creates a Clyde home and back it up. Used by clyde_home.""" # Make sure outside environment does not affect tests try: del os.environ["CLYDE_INST_DIR"] except KeyError: pass clyde_exe = _build_clyde() with TemporaryDirectory(prefix="clyde-functests") as tmp_dir: clyde_home = Path(tmp_dir) / "clyde_home" backup_dir = Path(tmp_dir) / "backup" os.environ["CLYDE_HOME"] = str(clyde_home) _run([clyde_exe, "setup"]) # Replace the installed Clyde binary with the one we just built shutil.copy(clyde_exe, get_bin_path("clyde")) shutil.move(clyde_home, backup_dir) yield clyde_home, backup_dir @pytest.fixture() def clyde_home(_setup_clyde_home): """Creates a Clyde home by reusing the Clyde home created by _setup_clyde_home()""" clyde_home, backup_dir = _setup_clyde_home rm_rf(clyde_home) shutil.copytree(backup_dir, clyde_home) yield clyde_home