Skip to content

Commit

Permalink
Merge pull request #3046 from boegel/EB_SCRIPT_PATH
Browse files Browse the repository at this point in the history
define $EB_SCRIPT_PATH in 'eb' wrapper script, and consider it before location of 'eb' determined via $PATH in get_paths_for function
  • Loading branch information
akesandgren authored Oct 4, 2019
2 parents 03e70cb + b63f805 commit 6c45977
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 7 deletions.
32 changes: 27 additions & 5 deletions easybuild/framework/easyconfig/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,17 +255,39 @@ def get_paths_for(subdir=EASYCONFIGS_PKG_SUBDIR, robot_path=None):
path_list.extend(sys.path)

# figure out installation prefix, e.g. distutils install path for easyconfigs
eb_path = which('eb')

# prefer using path specified in $EB_SCRIPT_PATH (if defined), which is set by 'eb' wrapper script
eb_path = os.getenv('EB_SCRIPT_PATH')
if eb_path is None:
# try to determine location of 'eb' script via $PATH, as fallback mechanism
eb_path = which('eb')
_log.info("Location to 'eb' script (found via $PATH): %s", eb_path)
else:
_log.info("Found location to 'eb' script via $EB_SCRIPT_PATH: %s", eb_path)

if eb_path is None:
warning_msg = "'eb' not found in $PATH, failed to determine installation prefix!"
_log.warning(warning_msg)
print_warning(warning_msg)
else:
# real location to 'eb' should be <install_prefix>/bin/eb
eb_path = resolve_path(eb_path)
# eb_path is location to 'eb' wrapper script, e.g. <install_prefix>/bin/eb
# so installation prefix is usually two levels up
install_prefix = os.path.dirname(os.path.dirname(eb_path))
path_list.append(install_prefix)
_log.debug("Also considering installation prefix %s..." % install_prefix)

# only consider resolved path to 'eb' script if desired subdir is not found relative to 'eb' script location
if os.path.exists(os.path.join(install_prefix, 'easybuild', subdir)):
path_list.append(install_prefix)
_log.info("Also considering installation prefix %s (determined via path to 'eb' script)...", install_prefix)
else:
_log.info("Not considering %s (no easybuild/%s subdir found)", install_prefix, subdir)

# also consider fully resolved location to 'eb' wrapper
# see https://github.com/easybuilders/easybuild-framework/pull/2248
resolved_eb_path = resolve_path(eb_path)
if eb_path != resolved_eb_path:
install_prefix = os.path.dirname(os.path.dirname(resolved_eb_path))
path_list.append(install_prefix)
_log.info("Also considering installation prefix %s (via resolved path to 'eb')...", install_prefix)

# look for desired subdirs
for path in path_list:
Expand Down
2 changes: 1 addition & 1 deletion easybuild/tools/filetools.py
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,7 @@ def find_eb_script(script_name):
prev_script_loc = script_loc

# fallback mechanism: check in location relative to location of 'eb'
eb_path = which('eb')
eb_path = os.getenv('EB_SCRIPT_PATH') or which('eb')
if eb_path is None:
_log.warning("'eb' not found in $PATH, failed to determine installation prefix")
else:
Expand Down
2 changes: 1 addition & 1 deletion easybuild/tools/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -1476,7 +1476,7 @@ def parse_external_modules_metadata(cfgs):
topdirs = [os.path.dirname(os.path.dirname(os.path.dirname(__file__)))]

# etc/ could also be located next to bin/
eb_cmd = which('eb')
eb_cmd = os.getenv('EB_SCRIPT_PATH') or which('eb')
if eb_cmd:
topdirs.append(os.path.dirname(os.path.dirname(eb_cmd)))

Expand Down
2 changes: 2 additions & 0 deletions eb
Original file line number Diff line number Diff line change
Expand Up @@ -90,5 +90,7 @@ then
export FANCYLOGGER_IGNORE_MPI4PY=1
fi

export EB_SCRIPT_PATH=$0

verbose "$PYTHON -m easybuild.main `echo \"$@\"`"
$PYTHON -m easybuild.main "$@"
48 changes: 48 additions & 0 deletions test/framework/easyconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -2562,8 +2562,12 @@ def test_get_paths_for(self):
test_ecs = os.path.join(top_dir, 'easyconfigs')
symlink(test_ecs, os.path.join(self.test_prefix, 'easybuild', 'easyconfigs'))

# temporarily mock stderr to avoid printed warning (because 'eb' is not available via $PATH)
self.mock_stderr(True)

# locations listed in 'robot_path' named argument are taken into account
res = get_paths_for(subdir='easyconfigs', robot_path=[self.test_prefix])
self.mock_stderr(False)
self.assertTrue(os.path.samefile(test_ecs, res[0]))

# easyconfigs location can also be derived from location of 'eb'
Expand All @@ -2588,6 +2592,50 @@ def test_get_paths_for(self):
res = get_paths_for(subdir='easyconfigs', robot_path=None)
self.assertTrue(os.path.samefile(test_ecs, res[0]))

# put mock 'eb' back in $PATH
os.environ['PATH'] = '%s:%s' % (os.path.join(self.test_prefix, 'bin'), orig_path)

# if $EB_SCRIPT_PATH is specified, this is picked up to determine location to easyconfigs
someprefix = os.path.join(self.test_prefix, 'someprefix')
test_easyconfigs_dir = os.path.join(someprefix, 'easybuild', 'easyconfigs')
mkdir(test_easyconfigs_dir, parents=True)
write_file(os.path.join(someprefix, 'bin', 'eb'), '')

# put symlink in place, both original path and resolved path should be considered
symlinked_prefix = os.path.join(self.test_prefix, 'symlinked_prefix')
symlink(someprefix, symlinked_prefix)

os.environ['EB_SCRIPT_PATH'] = os.path.join(symlinked_prefix, 'bin', 'eb')

res = get_paths_for(subdir='easyconfigs', robot_path=None)

# last path is symlinked path
self.assertEqual(res[-1], os.path.join(symlinked_prefix, 'easybuild', 'easyconfigs'))

# wipe sys.path. then only path found via $EB_SCRIPT_PATH is found
sys.path = []
res = get_paths_for(subdir='easyconfigs', robot_path=None)
self.assertEqual(len(res), 1)
self.assertEqual(res[0], os.path.join(symlinked_prefix, 'easybuild', 'easyconfigs'))

# if $EB_SCRIPT_PATH is not defined, then paths determined via 'eb' found through $PATH are picked up
del os.environ['EB_SCRIPT_PATH']

res = get_paths_for(subdir='easyconfigs', robot_path=None)
expected = os.path.join(self.test_prefix, 'easybuild', 'easyconfigs')
self.assertTrue(os.path.samefile(res[-1], expected))

# also check with $EB_SCRIPT_PATH set to a symlink which doesn't allow
# directly deriving path to easybuild/easyconfigs dir, but resolved symlink does
# cfr. https://github.com/easybuilders/easybuild-framework/pull/2248
eb_symlink = os.path.join(self.test_prefix, 'eb')
symlink(os.path.join(someprefix, 'bin', 'eb'), eb_symlink)
os.environ['EB_SCRIPT_PATH'] = eb_symlink

res = get_paths_for(subdir='easyconfigs', robot_path=None)
self.assertTrue(os.path.exists(res[0]))
self.assertTrue(os.path.samefile(res[0], os.path.join(someprefix, 'easybuild', 'easyconfigs')))

def test_is_generic_easyblock(self):
"""Test for is_generic_easyblock function."""

Expand Down

0 comments on commit 6c45977

Please sign in to comment.