Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

don't add directory that doesn't include any files to $PATH or $LD_LIBRARY_PATH #3769

Merged
merged 3 commits into from
Jul 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 19 additions & 14 deletions easybuild/framework/easyblock.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@
from easybuild.tools.py2vs3 import extract_method_name, string_type
from easybuild.tools.repository.repository import init_repository
from easybuild.tools.systemtools import check_linked_shared_libs, det_parallelism, get_shared_lib_ext, use_group
from easybuild.tools.utilities import INDENT_4SPACES, get_class_for, quote_str
from easybuild.tools.utilities import INDENT_4SPACES, get_class_for, nub, quote_str
from easybuild.tools.utilities import remove_unwanted_chars, time2str, trace_msg
from easybuild.tools.version import this_is_easybuild, VERBOSE_VERSION, VERSION

Expand Down Expand Up @@ -1429,9 +1429,17 @@ def make_module_req(self):
note += "for paths are skipped for the statements below due to dry run"
lines.append(self.module_generator.comment(note))

# for these environment variables, the corresponding subdirectory must include at least one file
keys_requiring_files = set(('PATH', 'LD_LIBRARY_PATH', 'LIBRARY_PATH', 'CPATH',
'CMAKE_PREFIX_PATH', 'CMAKE_LIBRARY_PATH'))
# For these environment variables, the corresponding directory must include at least one file.
# The values determine if detection is done recursively, i.e. if it accepts directories where files
# are only in subdirectories.
keys_requiring_files = {
'PATH': False,
'LD_LIBRARY_PATH': False,
'LIBRARY_PATH': True,
'CPATH': True,
'CMAKE_PREFIX_PATH': True,
'CMAKE_LIBRARY_PATH': True,
}

for key, reqs in sorted(requirements.items()):
if isinstance(reqs, string_type):
Expand Down Expand Up @@ -1461,19 +1469,16 @@ def make_module_req(self):
if fixed_paths != paths:
self.log.info("Fixed symlink lib64 in paths for %s: %s -> %s", key, paths, fixed_paths)
paths = fixed_paths
# remove duplicate paths
# don't use 'set' here, since order in 'paths' is important!
uniq_paths = []
for path in paths:
if path not in uniq_paths:
uniq_paths.append(path)
paths = uniq_paths
# remove duplicate paths preserving order
paths = nub(paths)
if key in keys_requiring_files:
# only retain paths that contain at least one file
recursive = keys_requiring_files[key]
retained_paths = [
path for path in paths
if os.path.isdir(os.path.join(self.installdir, path))
and dir_contains_files(os.path.join(self.installdir, path))
path
for path, fullpath in ((path, os.path.join(self.installdir, path)) for path in paths)
if os.path.isdir(fullpath)
and dir_contains_files(fullpath, recursive=recursive)
]
if retained_paths != paths:
self.log.info("Only retaining paths for %s that contain at least one file: %s -> %s",
Expand Down
13 changes: 10 additions & 3 deletions easybuild/tools/filetools.py
Original file line number Diff line number Diff line change
Expand Up @@ -1096,9 +1096,16 @@ def search_file(paths, query, short=False, ignore_dirs=None, silent=False, filen
return var_defs, hits


def dir_contains_files(path):
"""Return True if the given directory does contain any file in itself or any subdirectory"""
return any(files for _root, _dirs, files in os.walk(path))
def dir_contains_files(path, recursive=True):
"""
Return True if the given directory does contain any file

:recursive If False only the path itself is considered, else all subdirectories are also searched
"""
if recursive:
return any(files for _root, _dirs, files in os.walk(path))
else:
return any(os.path.isfile(os.path.join(path, x)) for x in os.listdir(path))


def find_eb_script(script_name):
Expand Down
19 changes: 19 additions & 0 deletions test/framework/easyblock.py
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,25 @@ def test_make_module_req(self):
else:
self.assertTrue(False, "Unknown module syntax: %s" % get_module_syntax())

# If PATH or LD_LIBRARY_PATH contain only folders, do not add an entry
sub_lib_path = os.path.join('lib', 'path_folders')
sub_path_path = os.path.join('bin', 'path_folders')
eb.make_module_req_guess = lambda: {'LD_LIBRARY_PATH': sub_lib_path, 'PATH': sub_path_path}
for path in (sub_lib_path, sub_path_path):
full_path = os.path.join(eb.installdir, path, 'subpath')
os.makedirs(full_path)
write_file(os.path.join(full_path, 'any.file'), 'test')
txt = eb.make_module_req()
if get_module_syntax() == 'Tcl':
self.assertFalse(re.search(r"prepend-path\s+LD_LIBRARY_PATH\s+\$%s\n" % sub_lib_path,
txt, re.M))
self.assertFalse(re.search(r"prepend-path\s+PATH\s+\$%s\n" % sub_path_path, txt, re.M))
else:
assert get_module_syntax() == 'Lua'
self.assertFalse(re.search(r'prepend_path\("LD_LIBRARY_PATH", pathJoin\(root, "%s"\)\)\n' % sub_lib_path,
txt, re.M))
self.assertFalse(re.search(r'prepend_path\("PATH", pathJoin\(root, "%s"\)\)\n' % sub_path_path, txt, re.M))

# cleanup
eb.close_log()
os.remove(eb.logfile)
Expand Down
5 changes: 5 additions & 0 deletions test/framework/filetools.py
Original file line number Diff line number Diff line change
Expand Up @@ -2330,21 +2330,26 @@ def makedirs_in_test(*paths):

empty_dir = makedirs_in_test('empty_dir')
self.assertFalse(ft.dir_contains_files(empty_dir))
self.assertFalse(ft.dir_contains_files(empty_dir, recursive=False))

dir_w_subdir = makedirs_in_test('dir_w_subdir', 'sub_dir')
self.assertFalse(ft.dir_contains_files(dir_w_subdir))
self.assertFalse(ft.dir_contains_files(dir_w_subdir, recursive=False))

dir_subdir_file = makedirs_in_test('dir_subdir_file', 'sub_dir_w_file')
ft.write_file(os.path.join(dir_subdir_file, 'sub_dir_w_file', 'file.h'), '')
self.assertTrue(ft.dir_contains_files(dir_subdir_file))
self.assertFalse(ft.dir_contains_files(dir_subdir_file, recursive=False))

dir_w_file = makedirs_in_test('dir_w_file')
ft.write_file(os.path.join(dir_w_file, 'file.h'), '')
self.assertTrue(ft.dir_contains_files(dir_w_file))
self.assertTrue(ft.dir_contains_files(dir_w_file, recursive=False))

dir_w_dir_and_file = makedirs_in_test('dir_w_dir_and_file', 'sub_dir')
ft.write_file(os.path.join(dir_w_dir_and_file, 'file.h'), '')
self.assertTrue(ft.dir_contains_files(dir_w_dir_and_file))
self.assertTrue(ft.dir_contains_files(dir_w_dir_and_file, recursive=False))

def test_find_eb_script(self):
"""Test find_eb_script function."""
Expand Down