diff --git a/mpsd-software-environment.py b/mpsd-software-environment.py index 60ae8443d11050ea802fe06b053b4b7b0fdd52f2..f60f88f86929df1a90c8cf2397252122ba7c4419 100755 --- a/mpsd-software-environment.py +++ b/mpsd-software-environment.py @@ -918,6 +918,84 @@ def start_new_environment(release, from_release, target_dir): raise NotImplementedError(msg) +def environment_status(mpsd_release: str, root_dir: Union[str, Path]) -> dict: + """Show status of release in installation. + + Parameters + ---------- + mpsd_release : str + A string representing the MPSD release version. + root_dir : pathlib.Path + A Path object pointing to the root directory of the installation. + Expect a subfolder root/mpsd_release in which we search for the + toolchains. + + Returns + ------- + toolchain_map : dict + A dictionary containing available microarchitectures as keys and + a list of available toolchains as values for each microarchitecture. + """ + msg = f"Showing status of release {mpsd_release} in {root_dir}" + logging.info(msg) + plog = logging.getLogger("print") + release_base_dir = root_dir / mpsd_release + microarch = get_native_microarchitecture() + toolchain_dir = release_base_dir / microarch + spack_dir = toolchain_dir / "spack" + + # if the mpsd_release does not exist: + if not release_base_dir.exists(): + logging.debug(f"Directory {str(release_base_dir)} does not exist.") + logging.error(f"MPSD release '{mpsd_release}' is not installed.") + return None + + # if the mpds_release directory exists but the spack repository is not fully + # cloned - indicates some kind of incomplete installation: + if not spack_dir.exists(): + logging.debug(f"Looking for files in {spack_dir}") + logging.error( + f"MPSD release '{mpsd_release}' has not been completely installed." + ) + + return None + + # find all folders for all microarch in the release directory + # except for the blacklisted files + black_listed_files = [ + config_vars["cmd_log_file"], + "spack-environments", + "logs", + "mpsd-spack-cache", + ] + + list_of_microarchs_candidates = os.listdir(release_base_dir) + list_of_microarchs = [ + x for x in list_of_microarchs_candidates if x not in black_listed_files + ] + logging.debug(f"{list_of_microarchs=}") + + toolchain_map = {} + for microarch in list_of_microarchs: + # get a list of all the toolchains in the microarch + possible_toolchains = (release_base_dir / microarch).glob( + "lmod/Core/toolchains/*.lua" + ) + # append toolchain which is the name of the file without the .lua extension + toolchain_map[microarch] = [toolchain.stem for toolchain in possible_toolchains] + + logging.debug(f"{toolchain_map=}") + + # pretty print the toolchain map key as the heading + # and the value as the list of toolchains + plog.info( + f"Toolchains installed in the {mpsd_release=} for each Microarchitecture:" + ) + for microarch, toolchains in toolchain_map.items(): + plog.info(f"- {microarch}: \n \t {toolchains}") + return toolchain_map + + def main(): """Execute main entry point.""" parser = argparse.ArgumentParser(description=about_tool) @@ -942,6 +1020,7 @@ def main(): ("reinstall", "Reinstall a software environment"), ("remove", "Remove a software environment or toolchains from an environment"), ("start-new", "Start a new software environment version"), + ("status", "Show the status of the software environment"), ] for cmd, help_text in list_of_cmds: subp = subparsers.add_parser(cmd, help=help_text) @@ -1017,6 +1096,8 @@ def main(): install_environment( args.release, args.toolchains, root_dir, False, args.enable_build_cache ) + elif args.action == "status": + _ = environment_status(args.release, script_dir) elif args.action == "prepare": prepare_environment(args.release, root_dir) elif args.action == "available": diff --git a/tests.py b/tests.py index a55f48b120c9d4b5ee6e9f58d1842516cbacd238..f8c0a106d99a6d867fe8807c40080b1d299b02b7 100644 --- a/tests.py +++ b/tests.py @@ -443,6 +443,32 @@ def test_create_log_file_names(): assert build_log_file_name is None +def test_environment_status(tmp_path): + """Test that the environment status is correct.""" + toolchain_map = mod.environment_status("fake-release", tmp_path) + assert toolchain_map is None + # create a fake environment + mpsd_release = "dev-23a" + test_microarch = mod.get_native_microarchitecture() + expected_toolchain_map = {test_microarch: ["foss2021a", "intel2021a"]} + for microarch in expected_toolchain_map.keys(): + toolchain_lmod_folder = ( + tmp_path / mpsd_release / microarch / "lmod" / "Core" / "toolchains" + ) + toolchain_lmod_folder.mkdir(parents=True) + spack_folder = tmp_path / mpsd_release / microarch / "spack" + spack_folder.mkdir(parents=True) + for toolchain in expected_toolchain_map[microarch]: + toolchain_file = toolchain_lmod_folder / f"{toolchain}.lua" + toolchain_file.touch() + + # check that the environment status is correct + toolchain_map = mod.environment_status(mpsd_release, tmp_path) + # convert each list to a set to ensure that the order doesn't matter + for microarch in expected_toolchain_map.keys(): + assert set(toolchain_map[microarch]) == set(expected_toolchain_map[microarch]) + + def test_interface(tmp_path): """Test other things (not implemented yet).""" pass