module files: system paths are excluded from path inspection (#5460)

closes #5201

Currently, if a user sets an external package to have a prefix that is
one of the system paths (like '/usr') the module files that are
generated will prepend '/usr/bin' to 'PATH', etc. This is particularly
nasty at the time when a module file is unloaded, and e.g. paths like
'/usr/bin' will be discarded from PATH.

This PR solves the issue skipping system paths when a prefix inspection
is made to generate module files.
This commit is contained in:
Massimiliano Culpo 2017-09-25 18:47:50 +02:00 committed by Todd Gamblin
parent 64311e8510
commit 8864d145e9
4 changed files with 72 additions and 11 deletions

View File

@ -502,25 +502,56 @@ def filter_environment_blacklist(env, variables):
yield item
def inspect_path(root, inspections):
"""Inspects a path to search for the subdirectories specified in the
inspection dictionary. Return a list of commands that will modify the
environment accordingly.
def inspect_path(root, inspections, exclude=None):
"""Inspects ``root`` to search for the subdirectories in ``inspections``.
Adds every path found to a list of prepend-path commands and returns it.
Args:
root: path where to search for subdirectories
inspections: dictionary that maps subdirectories to a list of
variables that we want to pre-pend with a path, if found
root (str): absolute path where to search for subdirectories
inspections (dict): maps relative paths to a list of environment
variables that will be modified if the path exists. The
modifications are not performed immediately, but stored in a
command object that is returned to client
exclude (callable): optional callable. If present it must accept an
absolute path and return True if it should be excluded from the
inspection
Examples:
The following lines execute an inspection in ``/usr`` to search for
``/usr/include`` and ``/usr/lib64``. If found we want to prepend
``/usr/include`` to ``CPATH`` and ``/usr/lib64`` to ``MY_LIB64_PATH``.
.. code-block:: python
# Set up the dictionary containing the inspection
inspections = {
'include': ['CPATH'],
'lib64': ['MY_LIB64_PATH']
}
# Get back the list of command needed to modify the environment
env = inspect_path('/usr', inspections)
# Eventually execute the commands
env.apply_modifications()
Returns:
instance of EnvironmentModifications containing the requested
modifications
"""
if exclude is None:
exclude = lambda x: False
env = EnvironmentModifications()
# Inspect the prefix to check for the existence of common directories
for relative_path, variables in inspections.items():
expected = os.path.join(root, relative_path)
if os.path.isdir(expected):
if os.path.isdir(expected) and not exclude(expected):
for variable in variables:
env.prepend_path(variable, expected)
return env

View File

@ -61,6 +61,7 @@
import spack.environment
import spack.tengine as tengine
import spack.util.path
import spack.util.environment
import spack.error
#: Root folders where the various module files should be written
@ -473,7 +474,9 @@ def environment_modifications(self):
"""List of environment modifications to be processed."""
# Modifications guessed inspecting the spec prefix
env = spack.environment.inspect_path(
self.spec.prefix, prefix_inspections
self.spec.prefix,
prefix_inspections,
exclude=spack.util.environment.is_system_path
)
# Modifications that are coded at package level

View File

@ -30,7 +30,7 @@
from spack.environment import EnvironmentModifications
from spack.environment import RemovePath, PrependPath, AppendPath
from spack.environment import SetEnv, UnsetEnv
from spack.util.environment import filter_system_paths
from spack.util.environment import filter_system_paths, is_system_path
def test_inspect_path(tmpdir):
@ -60,6 +60,20 @@ def test_inspect_path(tmpdir):
assert 'CPATH' in names
def test_exclude_paths_from_inspection():
inspections = {
'lib': ['LIBRARY_PATH', 'LD_LIBRARY_PATH'],
'lib64': ['LIBRARY_PATH', 'LD_LIBRARY_PATH'],
'include': ['CPATH']
}
env = environment.inspect_path(
'/usr', inspections, exclude=is_system_path
)
assert len(env) == 0
@pytest.fixture()
def prepare_environment_for_tests():
"""Sets a few dummy variables in the current environment, that will be

View File

@ -30,8 +30,21 @@
system_paths
def is_system_path(path):
"""Predicate that given a path returns True if it is a system path,
False otherwise.
Args:
path (str): path to a directory
Returns:
True or False
"""
return os.path.normpath(path) in system_dirs
def filter_system_paths(paths):
return [p for p in paths if os.path.normpath(p) not in system_dirs]
return [p for p in paths if not is_system_path(p)]
def get_path(name):