diff --git a/README.rst b/README.rst index e40c5d7ae7229dea2e6a3d726e87836ca21d419b..180fafaabea12ae8e587685b500d6275496c944e 100644 --- a/README.rst +++ b/README.rst @@ -33,18 +33,27 @@ To install, for example, the ``foss2022a-serial`` toolchain: $ cd /home/user/mpsd-software - Future calls of the `mpsd-software` command need to be executed from this - "mpsd-software-root" directory. +3. Initiate the installation at this location using:: -3. From the same directory, run the command to install the ``foss2022a-serial`` + $ mpsd-software init + + Future calls of the `mpsd-software` command need to be executed from this + "mpsd-software-root" directory or in one of its subdirectories. + + (The above command creates a hidden file ``.mpsd-software-root`` to tag the location for + as the root of the installation. All compiled files, logs etc are written in + or below this subdirectory.) + + +4. From the same directory, run the command to install the ``foss2022a-serial`` toolchain:: $ mpsd-software install dev-23a foss2022a-serial This will take some time (up to several hours depending on hardware). -4. To see the installation status, and the required ``module use`` command line +5. To see the installation status, and the required ``module use`` command line to activate the created modules, try the ``status`` command:: $ mpsd-software status dev-23a @@ -55,7 +64,7 @@ To install, for example, the ``foss2022a-serial`` toolchain: foss2022a-serial [module use /home/user/mpsd-software/dev-23a/cascadelake/lmod/Core] -5. To compile Octopus, source the provided configure script, for example ``foss2022a-serial-config.sh``, as +6. To compile Octopus, source the provided configure script, for example ``foss2022a-serial-config.sh``, as `explained here <https://computational-science.mpsd.mpg.de/docs/mpsd-hpc.html#loading-a-toolchain-to-compile-octopus>`__). The configure scripts are located in ``dev-23a/spack-environments/octopus``:: @@ -265,15 +274,3 @@ Frequently asked questions Development ----------- Developers documentation is available at development.rst. - - -.. comment: - Draft for additional steps for 'quickstart' once/if we have the the `init` command added. - - 3. Initiate the installation at this location using:: - - $ mpsd-software init - - (This creates a hidden file ``.mpsd-software-root`` to tag the location for - as the root of the installation. All compiled files, logs etc are written in - or below this subdirectory.) diff --git a/src/mpsd_software_manager/mpsd_software.py b/src/mpsd_software_manager/mpsd_software.py index 7121469e5cc6cddd09edfe2e0a1b0487fb68cc25..364485ad60f6b450ee647505f3b264ef2c543dbd 100755 --- a/src/mpsd_software_manager/mpsd_software.py +++ b/src/mpsd_software_manager/mpsd_software.py @@ -1115,6 +1115,53 @@ def initialize_environment(root_dir: Path) -> None: ) +def get_root_dir() -> Path: + """Get the root directory of the installation. + + Look for the hidden file ``.mpsd-software-root`` + (defined in config_vars["init_file"]) + in the current directory, or any parent directory. + If found, return the path to the root directory + of the MPSD software instance. + If not found, exit with an error message. + + Returns + ------- + root_dir : pathlib.Path + A Path object pointing to the root directory of the installation. + This folder contains the hidden file ``.mpsd-software-root``, + ``mpsd_releases`` ( for eg ``dev-23a``) and ``mpsd-spack-cache``. + + + """ + # check if the root_dir is not already initialized + script_call_dir = Path.cwd() + init_file = script_call_dir / config_vars["init_file"] + if init_file.exists(): + return script_call_dir + + # if not, look for the init file in the parent directories + for parent_folder in script_call_dir.parents: + init_file = parent_folder / config_vars["init_file"] + if init_file.exists(): + script_call_dir = parent_folder + return script_call_dir + + # if not found in any parent directory, exit with an error message + logging.getLogger("print").info( + "Error: Couldnt find MPSD software instance" + "in the current directory or any parent directory. \n" + f"Directory {str(script_call_dir)} is not a MPSD software instance. \n" + "Please run 'mpsd-software init' to " + "initialise the software instance here, \n" + "or switch to a directory which is already initialised.\n \n" + f"Hint: Look for the directory containing `{config_vars['cmd_log_file']}`" + + f"and the hidden file `{config_vars['init_file']}`." + " to check if a directory is initialised" + ) + sys.exit(1) + + def main(): """Execute main entry point.""" parser = argparse.ArgumentParser( @@ -1200,32 +1247,41 @@ def main(): # Carry out the action args = parser.parse_args() - # root dir is the place where this script is called from - root_dir = Path(os.getcwd()) + # 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) - # set up logging for all actions except init - if args.action != "init": - log_file = get_installer_log_file_path(args.release, args.action, root_dir) - else: - log_file = None + # Check if the action is init + # if so, call the init function and exit + if args.action == "init": + initialize_environment(Path(os.getcwd())) + sys.exit(0) + + # root_dir is the place where this MPSD software instance has its root + root_dir = get_root_dir() + + # set up logging ( with file handler) for all actions (except init) + log_file = get_installer_log_file_path( + args.release, + args.action, + root_dir, + ) set_up_logging( args.loglevel, log_file, ) # sanity check for common mistakes in command line arguments - if args.action != "init": - if args.release.endswith("/"): # happens easily with autocompletion - logging.error( - f"You provided mpsd-release='{args.release}'. " - f"Did you mean '{args.release.removesuffix('/')}'?" - ) - sys.exit(1) + if args.release.endswith("/"): # happens easily with autocompletion + logging.error( + f"You provided mpsd-release='{args.release}'. " + f"Did you mean '{args.release.removesuffix('/')}'?" + ) + sys.exit(1) # Check the command and run related function - if args.action == "init": - initialize_environment(root_dir) - elif args.action == "remove": + if args.action == "remove": remove_environment(args.release, root_dir, args.package_set) elif args.action == "start-new": start_new_environment(args.from_release, args.to_release, root_dir) diff --git a/tests/test_mpsd_software.py b/tests/test_mpsd_software.py index 3ebd1fd69982ebb3883ac1ebd99eca4c3a46e8ed..79fc35cea3ee48a3f7f625abd3495bd607bcf51c 100644 --- a/tests/test_mpsd_software.py +++ b/tests/test_mpsd_software.py @@ -539,6 +539,34 @@ def test_initialize_environment(tmp_path): assert pytest_wrapped_e.value.code == 1 +def test_get_root_dir(tmp_path): + """Test that the root directory is correct.""" + with mod.os_chdir(tmp_path): + # test that function exists with error 1 if root dir doesn't exist + with pytest.raises(SystemExit) as pytest_wrapped_e: + mod.get_root_dir() + assert pytest_wrapped_e.type == SystemExit + assert pytest_wrapped_e.value.code == 1 + + # test that initialize_environment creates the root dir + mod.initialize_environment(tmp_path) + root_dir = mod.get_root_dir() + assert root_dir == tmp_path + + # test that root_dir from parent is detected correctly + sub_dir = tmp_path / "sub_dir" + sub_dir.mkdir() + with mod.os_chdir(sub_dir): + root_dir = mod.get_root_dir() + assert root_dir == tmp_path + + # test that initialising in a subdirectory makes it the root dir + with mod.os_chdir(sub_dir): + mod.initialize_environment(sub_dir) + root_dir = mod.get_root_dir() + assert root_dir == sub_dir + + def test_interface(tmp_path): """Test other things (not implemented yet).""" pass