Newer
Older
"""mpsd-software: entry point for command line application."""
import logging
from .cmds.available import get_available_package_sets, get_available_releases
from .cmds.init import initialise_environment
from .cmds.install import install_environment
from .cmds.prepare import prepare_environment
from .cmds.remove import remove_environment
from .cmds.status import environment_status
from .utils.filesystem_utils import get_root_dir
from .utils.logging import (
get_log_file_path,
record_script_execution_summary,
set_up_logging,
)
from mpsd_software_manager import __version__, command_name
# command_name = Path(sys.argv[0]).name
This tool builds software package sets (including toolchains for Octopus).
It follows recipes as used on the MPSD HPC system and the (spack-based)
Octopus buildbot. Compiled software is organised into MPSD software release
versions (such as `dev-23a`) and CPU microarchitecture (such as `sandybridge`).
Compiled packages and toolchains can be activated and used via `module load` as
on the HPC system.
Further documentation is available in the README.rst file, online at
https://gitlab.gwdg.de/mpsd-cs/mpsd-software-manager/-/blob/main/README.rst
$> {command_name}
"""
about_epilog = f"""
Examples:
1. Query what releases are available for installation
$> {command_name} available
2. Query what package sets and toolchains are available for installation in
$> {command_name} available dev-23a
3. Install foss2022a-serial toolchain from the dev-23a release
$> {command_name} install dev-23a foss2022a-serial
4. Check what package sets and toolchains are installed from release dev-23a
$> {command_name} status dev-23a
The `status` command also displays the `module use` command needed to load
the created modules.
# TODO @Ashwin
# Martin: Do we still need this function?
# It seems to be similar to 'prepare'; the parser does not offer it.
def start_new_environment(release, from_release, target_dir):
"""Start new MPSD software environment version."""
msg = f"Starting new release {release} from {from_release} to {target_dir}"
logging.info(msg)
raise NotImplementedError(msg)
parser = argparse.ArgumentParser(
description=about_intro,
epilog=about_epilog,
formatter_class=argparse.RawDescriptionHelpFormatter,
)
parser.add_argument(
"-l",
dest="loglevel",
choices=["warning", "info", "debug"],
required=False,
default="warning",
help="Set the log level",
)
parser.add_argument("--version", action="version", version=__version__)

Ashwin Kumar Karnad
committed
parser.add_argument(

Ashwin Kumar Karnad
committed
"--develop",
action="store_true",
default=False,
help="Allow the use of unreleased branches",

Ashwin Kumar Karnad
committed
)
dest="action",
title="actions",
description="valid actions", # required=True
subparsers.required = True
list_of_cmds = [
("init", "Initialise the MPSD software instance in the current directory"),
("available", "What is available for installation?"),
("install", "Install a software environment"),
# ("reinstall", "Reinstall a package_set"),
# ("start-new", "Start a new MPSD software release version"),
("status", "Show status: what is installed?"),
("prepare", "Prepare installation of MPSD-release (dev only)"),
]
for cmd, help_text in list_of_cmds:
subp = subparsers.add_parser(cmd, help=help_text)
if cmd == "start-new":
subp.add_argument(
"--from-release",
dest="from_release",
type=str,
required=True,
help="Release version to start from",
)
subp.add_argument(
"--to-release",
dest="to_release",
type=str,
required=True,
help="Release version to create",
)
# most commands except need a release version
if cmd in ["install", "prepare", "reinstall", "remove"]:
subp.add_argument(
"release",
type=str,
help="Release version to prepare, install, reinstall or remove",
)
# for some commands the release version is optional
subp.add_argument(
"release",
type=str,
nargs="?",
help="Release version to prepare, install, reinstall or remove",
)
if cmd in ["install", "reinstall", "remove"]:
package_set_help = (
f"One or more package sets (like toolchains) to be {cmd}ed. "
"Use 'ALL' to refer to all available package sets."
"package_set", # first option defines attribute
# name `args.package_set` in `args = parser_args()`
default="NONE",
help=package_set_help,
# TODO Move the enable-build-cache flag to only 'install' cmd
subp.add_argument(
"--enable-build-cache",
action="store_true",
"Enable Spack build cache. Useful for reinstallation but "
"consumes time and disk space."
if cmd in ["status"]:
subp.add_argument(
type=str,
nargs="?",
default="NONE",
help="Package set to show status for.",
)
# Carry out the action
args = parser.parse_args()
# Set up logging without file handle:
# this is used in the init action and for logging the
# get_root_dir() function
set_up_logging(args.loglevel)
# Check if the action is init
# if so, call the init function and exit
if args.action == "init":
initialise_environment(Path(os.getcwd()))
# if a release version is specified:
if (
args.release
# sanity check for common mistakes in command line arguments
and args.release.endswith("/") # happens easily with autocompletion
):
removesuffix = lambda s, p: s[: -len(p)] if p and s.endswith(p) else s # noqa: E731
args.release = removesuffix(args.release, "/")
logging.warning(f"Removed trailing slash from release: {args.release}")
# root_dir is the place where this MPSD software instance has its root
# set up logging filename: we record activities that change the installation
if args.action in ["init", "install", "prepare", "reinstall", "remove"]:
args.action,
root_dir,
)
# some commands do not write any log_files:
elif args.action in ["available", "status"]:
else:
# sanity check
raise NotImplementedError(
f"Should never happen: unknown args.action={args.action}"
)
if args.action not in ["status", "available"]:
# record the script execution summary only if
# the action is one that changes files on disk
record_script_execution_summary(root_dir, apex_log_file)
remove_environment(args.release, root_dir, args.package_set)
start_new_environment(args.from_release, args.to_release, root_dir)
args.release, args.package_set, root_dir, args.enable_build_cache
environment_status(args.release, root_dir, args.package_set)
prepare_environment(args.release, root_dir, args.develop)

Ashwin Kumar Karnad
committed
get_available_package_sets(args.release, args.develop)
else:
get_available_releases(print_result=True)
sys.exit(0)
message = f"No known action found (args.action={args.action}). Should probably never happen." # noqa: E501
logging.error(message)
raise NotImplementedError(message)
# TODO Martin: This can be removed (will do that separately)