"""
To append instructions in modulefile.
"""
import os
from pathlib import Path
from typing import Any, List, Tuple
from venvmod.tools import get_std_name, logger
from . import get_module_filepath, get_parser
from ..tools import check_raise
[docs]
def append_command(arguments: Tuple[str, str, str],
description: str,
positionals: List[Tuple[str, Any, str, Any]],
command: str):
"""Append a command to a modulefile.
Parameters
----------
arguments : Tuple[str, str, str]
If None, arguments are read from :func:`venvmod.commands.get_parser.get_parser` function,
else ``(virtual_env, appli, arguments)`` given as str
description : str
Description of the command provided to ``get_parser`` function if ``arguments`` is None.
positionals: List[Tuple[str, Any, str, Any]], optional
list of positionals ('name', default, 'help', nargs), by default None
command : str
Name of the command
"""
if arguments is None:
options = get_parser(description=description,
positionals=positionals,
with_appli=True)
virtual_env = options.virtual_env
logger.debug("append_command virtual_env '%s'", virtual_env)
appli = options.appli
logger.debug("append_command appli '%s'", appli)
arguments = ""
for positional in positionals:
values = vars(options)[positional[0]]
logger.debug("append_command positional '%s': '%s'", positional, values)
arguments += " " + " ".join(values)
else:
virtual_env, appli, arguments = arguments
filepath = get_module_filepath(virtual_env=Path(virtual_env).absolute(), appli_name=appli)
check_raise(not filepath.exists(), FileNotFoundError,
f"You can't add command to non exsting modulefile {filepath}."
f" You may need to run 'venvmod-initialize {virtual_env}'"
f" or 'venvmod-add-appli {virtual_env} {filepath.name}' first.")
with filepath.open(mode='a', encoding='utf-8') as modulefile:
modulefile.write(f"{command} {arguments}\n")
[docs]
def module_use(arguments: Tuple[str, str, str] = None):
"""Add a 'module use' command to a modulefile.
Paths to use are given as str in the last value of ``arguments``.
Parameters
----------
arguments : Tuple[str, str, str], optional
See ``append_command`` function, by default None
"""
append_command(arguments,
description="Add dir(s) to MODULEPATH variable.",
positionals=[("PATH", [], "List of paths to use to locate modules", '+')],
command="module use")
[docs]
def module_load(arguments: Tuple[str, str, str] = None):
"""Add a 'module load' command to a modulefile.
Modules to load are given as str in the last value of ``arguments``.
Parameters
----------
arguments : Tuple[str, str, str], optional
See ``append_command`` function, by default None
"""
append_command(arguments,
description="Load modulefile(s).",
positionals=[("MODULE", [], "List of environment module to load", '+')],
command="module load")
[docs]
def source_sh(arguments: Tuple[str, str, str] = None):
"""Add a 'source-sh' command to a modulefile.
Shell + file to source + args are given as str in the last value of ``arguments``.
Parameters
----------
arguments : Tuple[str, str, str], optional
See ``append_command`` function, by default None
"""
append_command(arguments,
description="Script(s) to source.",
positionals=[("SHELL", [], "Shell name", 1),
("SCRIPT", [], "Script path", 1),
("ARG", [], "Script arguments", "*")],
command="source-sh")
[docs]
def prepend_path(arguments: Tuple[str, str, str] = None):
"""Add a 'prepent-path' command to a modulefile.
Env var + paths to prepend are given as str in the last value of ``arguments``.
Parameters
----------
arguments : Tuple[str, str, str], optional
See ``append_command`` function, by default None
"""
append_command(arguments,
description="Prepend value to environment variable.",
positionals=[("ENV_VAR", [], "Variable to prepend", 1),
("PATH", [], "List of paths to prepend", '+')],
command="prepend-path")
[docs]
def append_path(arguments: Tuple[str, str, str] = None):
"""Add a 'append-path' command to a modulefile.
Env var + paths to append are given as str in the last value of ``arguments``.
Parameters
----------
arguments : Tuple[str, str, str], optional
See ``append_command`` function, by default None
"""
append_command(arguments,
description="Append value to environment variable.",
positionals=[("ENV_VAR", [], "Variable to append", 1),
("PATH", [], "List of paths to append", '+')],
command="append-path")
[docs]
def setenv(arguments: Tuple[str, str, str] = None):
"""Add a 'setenv' command to a modulefile.
Env var + value to define are given as str in the last value of ``arguments``.
Parameters
----------
arguments : Tuple[str, str, str], optional
See ``append_command`` function, by default None
"""
append_command(arguments,
description="Define environment variable.",
positionals=[("VARIABLE", [], "Environment variable to define", 1),
("VALUE", [], "Value associated to the variable", 1)],
command="setenv")
[docs]
def remove_path(arguments: Tuple[str, str, str] = None):
"""Add a 'remove-path' command to a modulefile.
Env var + value to remove are given as str in the last value of ``arguments``.
Parameters
----------
arguments : Tuple[str, str, str], optional
See ``append_command`` function, by default None
"""
append_command(arguments,
description="Remove value from environment variable.",
positionals=[("VARIABLE", [], "Environment variable to modify", 1),
("PATH", [], "Path to remove from variable", 1)],
command="remove-path")
[docs]
def set_aliases(arguments: Tuple[str, str, str] = None):
"""Add a 'set-alias' command to a modulefile.
Alias to define are given as str in the last value of ``arguments``.
Parameters
----------
arguments : Tuple[str, str, str], optional
See ``append_command`` function, by default None
"""
append_command(arguments,
description="Define aliases.",
positionals=[("ALIAS", [], "Alias name", 1),
("VALUE", [], "Alias value", 1)],
command="set-alias")
[docs]
def read_env(arguments: Tuple[str, str] = None): # pylint: disable=too-many-branches
"""Add commands to a modulefile from environment variables.
Parse ``os.environ`` to look at variable starting with 'appli' (case insensitive) name.
For thoses variables, append commands for the following suffixes:
- "LD_LIBRARY_PATH", "PYTHONPATH", "PATH": ``prepend``
- "MODULE_USE": ``module use``
- "MODULEFILES": ``module load``
- "SOURCEFILES": ``source-sh`` for each element 'shell script [args...]' separated by ';'
- "EXPORTS": ``setenv`` for each element 'var=value' separated by ' '
- "ALIASES": ``set-alias`` for each element 'var=value' separated by ' '
- "REMOVE_PATHS": ``remove-path`` for each element 'var=value' separated by ' '
Examples
--------
The following ::
$ export MY_APPLI_LD_LIBRARY_PATH="/path/to/lib1:/path/to/lib2"
$ venvmod-cmd-read-env --appli MY_APPLI
will prepend "LD_LIBRARY_PATH" with "/path/to/lib1:/path/to/lib2" in "my_appli" module.
Parameters
----------
arguments : Tuple[str, str], optional, by default None
If None, arguments are read from ``get_parser`` function,
else ``(virtual_env, appli)`` given as str
"""
if arguments is None:
options = get_parser(description="Read environment variable to extend modulefile.",
with_appli=True)
appli = options.appli if options.appli else options.virtual_env
appli = get_std_name(str(Path(appli).name)) # virtual_env may be a path
virtual_env = options.virtual_env
else:
virtual_env, appli = arguments
# List env vars
appli_env_vars = {envvar: value for envvar, value in os.environ.items()
if get_std_name(envvar).startswith(appli.replace('.', '_'))}
logger.debug("read_env: os.environ = '%s'", os.environ)
logger.debug("read_env: appli_env_vars = '%s'", appli_env_vars)
# Source file in first
_read_src_files(virtual_env, appli_env_vars, appli)
# modules
_read_modules(virtual_env, appli_env_vars, appli)
# prepend
_read_prepend(virtual_env, appli_env_vars, appli)
# other, remove is at the end
_read_others(virtual_env, appli_env_vars, appli)
def _read_src_files(virtual_env, appli_env_vars, appli):
for envvar, value in appli_env_vars.copy().items():
if envvar.endswith("SOURCEFILES"):
for var in value.split(";"):
if var:
source_sh(arguments=(virtual_env, appli, var))
appli_env_vars.pop(envvar)
break
def _read_modules(virtual_env, appli_env_vars, appli):
for suffix, function in {
"MODULE_USE": module_use,
"MODULEFILES": module_load}.items():
for envvar, value in appli_env_vars.copy().items():
if envvar.endswith(suffix):
function(arguments=(virtual_env, appli, value))
appli_env_vars.pop(envvar)
def _read_prepend(virtual_env, appli_env_vars, appli):
for var_path in ["LD_LIBRARY_PATH", "PYTHONPATH", "PATH"]:
for envvar, value in appli_env_vars.copy().items():
if envvar.endswith(var_path):
for var in reversed(value.split(":")):
if var:
prepend_path(arguments=(virtual_env, appli, f"{var_path} {var}"))
appli_env_vars.pop(envvar)
def _read_others(virtual_env, appli_env_vars, appli):
for suffix, function in {
"EXPORTS": setenv,
"ALIASES": set_aliases,
"REMOVE_PATHS": remove_path}.items():
for envvar, value in appli_env_vars.copy().items():
if envvar.endswith(suffix):
for var in value.split():
if var:
function(arguments=(virtual_env, appli, var.replace("=", " ")))
appli_env_vars.pop(envvar)