Skip to content

Commit 37b3421

Browse files
authored
Merge branch 'develop' into arch-specific-deps-for-java
2 parents e94fe12 + 752ce42 commit 37b3421

34 files changed

+610
-110
lines changed

RELEASE_NOTES

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,29 @@ For more detailed information, please see the git log.
33

44
These release notes can also be consulted at https://easybuild.readthedocs.io/en/latest/Release_notes.html.
55

6+
v4.0.1 (October 15th 2019)
7+
--------------------------
8+
9+
update/bugfix release
10+
11+
- various enhancements, including:
12+
- add 'parallel' to list of config templates (#3036)
13+
- add GitHub Actions workflow to run easybuild-framework test suite (#3039)
14+
- add 'retest' as a reason to --close-pr, to close/re-open PRs to trigger re-test in Travis (#3040)
15+
- define $EB_SCRIPT_PATH in 'eb' wrapper script, and consider it before location of 'eb' determined via $PATH in get_paths_for function (#3046)
16+
- add support for --remove-ghost-install-dirs configuration option, and warn about (potential) ghost install dirs by default when --force/--rebuild is used (#3050)
17+
- various bug fixes, including:
18+
- update bootstrap script to support installing EasyBuild v4.0 (#3017)
19+
- fix broken test_download_repo due to archiving of easyconfigs (#3019, #3023)
20+
- avoid that --inject-checksums introduces list of patches for extensions as a single long line (#3025, #3034)
21+
- enhance regex in fix_shebang method to fix more Python/Perl shebangs + avoid patching binary files (#3029)
22+
- delete test gist that is created by --check-github (#3031)
23+
- disable templates when defining easyconfig parameters in EasyConfig.set_keys() (#3037)
24+
- avoid setting GC3Pie's max_in_flight to None if --job-max-jobs is not specified (#3038)
25+
- fix use of obtain_file method for extensions (#3042)
26+
- error out if some GC3Pie job failed (#3044)
27+
28+
629
v4.0.0 (September 20th 2019)
730
----------------------------
831

easybuild/base/fancylogger.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,9 @@ def getLogger(name=None, fname=False, clsname=False, fancyrecord=None):
452452
nameparts = []
453453

454454
if not is_fancyroot():
455-
nameparts.append(getRootLoggerName())
455+
# deliberately not calling getRootLoggerName function to determine actual root logger name,
456+
# because it is prohibitively expensive in some texts (even when using 'python -O')
457+
nameparts.append('root')
456458

457459
if fancyrecord is None:
458460
# Altough we could set it as default value in the function definition

easybuild/framework/easyblock.py

Lines changed: 42 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@
7575
from easybuild.tools.filetools import change_dir, convert_name, compute_checksum, copy_file, derive_alt_pypi_url
7676
from easybuild.tools.filetools import diff_files, download_file, encode_class_name, extract_file
7777
from easybuild.tools.filetools import find_backup_name_candidate, get_source_tarball_from_git, is_alt_pypi_url
78-
from easybuild.tools.filetools import is_sha256_checksum, mkdir, move_file, move_logs, read_file, remove_file, rmtree2
79-
from easybuild.tools.filetools import verify_checksum, weld_paths, write_file
78+
from easybuild.tools.filetools import is_sha256_checksum, mkdir, move_file, move_logs, read_file, remove_dir
79+
from easybuild.tools.filetools import remove_file, rmtree2, verify_checksum, weld_paths, write_file
8080
from easybuild.tools.hooks import BUILD_STEP, CLEANUP_STEP, CONFIGURE_STEP, EXTENSIONS_STEP, FETCH_STEP, INSTALL_STEP
8181
from easybuild.tools.hooks import MODULE_STEP, PACKAGE_STEP, PATCH_STEP, PERMISSIONS_STEP, POSTITER_STEP, POSTPROC_STEP
8282
from easybuild.tools.hooks import PREPARE_STEP, READY_STEP, SANITYCHECK_STEP, SOURCE_STEP, TEST_STEP, TESTCASES_STEP
@@ -453,8 +453,8 @@ def fetch_patches(self, patch_specs=None, extension=False, checksums=None):
453453
raise EasyBuildError('No file found for patch %s', patch_spec)
454454

455455
if extension:
456-
self.log.info("Fetched extension patches: %s" % patches)
457-
return [patch['path'] for patch in patches]
456+
self.log.info("Fetched extension patches: %s", patches)
457+
return patches
458458
else:
459459
self.log.info("Added patches: %s" % self.patches)
460460

@@ -544,6 +544,7 @@ def fetch_extension_sources(self, skip_checksums=False):
544544

545545
if not skip_checksums:
546546
for patch in ext_patches:
547+
patch = patch['path']
547548
# report both MD5 and SHA256 checksums,
548549
# since both are valid default checksum types
549550
for checksum_type in (CHECKSUM_TYPE_MD5, CHECKSUM_TYPE_SHA256):
@@ -553,6 +554,7 @@ def fetch_extension_sources(self, skip_checksums=False):
553554
# verify checksum (if provided)
554555
self.log.debug('Verifying checksums for extension patches...')
555556
for idx, patch in enumerate(ext_patches):
557+
patch = patch['path']
556558
checksum = self.get_checksum_for(checksums[1:], filename=patch, index=idx)
557559
if verify_checksum(patch, checksum):
558560
self.log.info('Checksum for extension patch %s verified', patch)
@@ -924,25 +926,19 @@ def make_dir(self, dir_name, clean, dontcreateinstalldir=False):
924926
if os.path.exists(dir_name):
925927
self.log.info("Found old directory %s" % dir_name)
926928
if self.cfg['keeppreviousinstall']:
927-
self.log.info("Keeping old directory %s (hopefully you know what you are doing)" % dir_name)
929+
self.log.info("Keeping old directory %s (hopefully you know what you are doing)", dir_name)
928930
return
929-
elif clean:
930-
try:
931-
rmtree2(dir_name)
932-
self.log.info("Removed old directory %s" % dir_name)
933-
except OSError as err:
934-
raise EasyBuildError("Removal of old directory %s failed: %s", dir_name, err)
935931
elif build_option('module_only'):
936932
self.log.info("Not touching existing directory %s in module-only mode...", dir_name)
933+
elif clean:
934+
remove_dir(dir_name)
935+
self.log.info("Removed old directory %s", dir_name)
937936
else:
938937
self.log.info("Moving existing directory %s out of the way...", dir_name)
939-
try:
940-
timestamp = time.strftime("%Y%m%d-%H%M%S")
941-
backupdir = "%s.%s" % (dir_name, timestamp)
942-
shutil.move(dir_name, backupdir)
943-
self.log.info("Moved old directory %s to %s" % (dir_name, backupdir))
944-
except OSError as err:
945-
raise EasyBuildError("Moving old directory to backup %s %s failed: %s", dir_name, backupdir, err)
938+
timestamp = time.strftime("%Y%m%d-%H%M%S")
939+
backupdir = "%s.%s" % (dir_name, timestamp)
940+
move_file(dir_name, backupdir)
941+
self.log.info("Moved old directory %s to %s", dir_name, backupdir)
946942

947943
if dontcreateinstalldir:
948944
olddir = dir_name
@@ -1619,6 +1615,31 @@ def set_parallel(self):
16191615
self.cfg['parallel'] = det_parallelism(par=par, maxpar=self.cfg['maxparallel'])
16201616
self.log.info("Setting parallelism: %s" % self.cfg['parallel'])
16211617

1618+
def remove_module_file(self):
1619+
"""Remove module file (if it exists), and check for ghost installation directory (and deal with it)."""
1620+
1621+
if os.path.exists(self.mod_filepath):
1622+
# if installation directory used by module file differs from the one used now,
1623+
# either clean it up to avoid leaving behind a ghost installation, or warn about it
1624+
# (see also https://github.com/easybuilders/easybuild-framework/issues/3026)
1625+
old_installdir = self.module_generator.det_installdir(self.mod_filepath)
1626+
1627+
if old_installdir is None:
1628+
warning_msg = "Failed to determine installation directory from module file %s" % self.mod_filepath
1629+
warning_msg += ", can't clean up potential ghost installation for %s %s" % (self.name, self.version)
1630+
print_warning(warning_msg)
1631+
1632+
elif os.path.exists(old_installdir) and not os.path.samefile(old_installdir, self.installdir):
1633+
if build_option('remove_ghost_install_dirs'):
1634+
remove_dir(old_installdir)
1635+
self.log.info("Ghost installation directory %s removed", old_installdir)
1636+
print_msg("Ghost installation directory %s removed", old_installdir)
1637+
else:
1638+
print_warning("Likely ghost installation directory detected: %s", old_installdir)
1639+
1640+
self.log.info("Removing existing module file %s", self.mod_filepath)
1641+
remove_file(self.mod_filepath)
1642+
16221643
#
16231644
# STEP FUNCTIONS
16241645
#
@@ -1669,9 +1690,7 @@ def check_readiness_step(self):
16691690

16701691
# remove existing module file under --force (but only if --skip is not used)
16711692
elif build_option('force') or build_option('rebuild'):
1672-
if os.path.exists(self.mod_filepath):
1673-
self.log.info("Removing existing module file %s", self.mod_filepath)
1674-
remove_file(self.mod_filepath)
1693+
self.remove_module_file()
16751694

16761695
def fetch_step(self, skip_checksums=False):
16771696
"""Fetch source files and patches (incl. extensions)."""
@@ -3467,8 +3486,8 @@ def make_checksum_lines(checksums, indent_level):
34673486
print_msg(" * %s: %s" % (src_fn, checksum), log=_log)
34683487
ext_checksums.append((src_fn, checksum))
34693488
for ext_patch in ext.get('patches', []):
3470-
patch_fn = os.path.basename(ext_patch)
3471-
checksum = compute_checksum(ext_patch, checksum_type)
3489+
patch_fn = os.path.basename(ext_patch['path'])
3490+
checksum = compute_checksum(ext_patch['path'], checksum_type)
34723491
print_msg(" * %s: %s" % (patch_fn, checksum), log=_log)
34733492
ext_checksums.append((patch_fn, checksum))
34743493

easybuild/framework/easyconfig/easyconfig.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
from easybuild.tools.module_naming_scheme.utilities import avail_module_naming_schemes, det_full_ec_version
6868
from easybuild.tools.module_naming_scheme.utilities import det_hidden_modname, is_valid_module_name
6969
from easybuild.tools.modules import modules_tool
70-
from easybuild.tools.py2vs3 import OrderedDict, string_type
70+
from easybuild.tools.py2vs3 import OrderedDict, create_base_metaclass, string_type
7171
from easybuild.tools.systemtools import check_os_dependency, get_cpu_architecture
7272
from easybuild.tools.toolchain.toolchain import SYSTEM_TOOLCHAIN_NAME, is_system_toolchain
7373
from easybuild.tools.toolchain.toolchain import TOOLCHAIN_CAPABILITIES, TOOLCHAIN_CAPABILITY_CUDA
@@ -530,12 +530,15 @@ def extend_params(self, extra, overwrite=True):
530530
self.mandatory.append(key)
531531
self.log.debug("Updated list of mandatory easyconfig parameters: %s", self.mandatory)
532532

533-
def copy(self):
533+
def copy(self, validate=None):
534534
"""
535535
Return a copy of this EasyConfig instance.
536536
"""
537+
if validate is None:
538+
validate = self.validation
539+
537540
# create a new EasyConfig instance
538-
ec = EasyConfig(self.path, validate=self.validation, hidden=self.hidden, rawtxt=self.rawtxt)
541+
ec = EasyConfig(self.path, validate=validate, hidden=self.hidden, rawtxt=self.rawtxt)
539542
# take a copy of the actual config dictionary (which already contains the extra options)
540543
ec._config = copy.deepcopy(self._config)
541544
# since rawtxt is defined, self.path may not get inherited, make sure it does
@@ -2238,10 +2241,12 @@ def fix_deprecated_easyconfigs(paths):
22382241
print_msg("\nAll done! Fixed %d easyconfigs (out of %d found).\n", fixed_cnt, cnt, prefix=False)
22392242

22402243

2241-
class ActiveMNS(object):
2242-
"""Wrapper class for active module naming scheme."""
2244+
# singleton metaclass: only one instance is created
2245+
BaseActiveMNS = create_base_metaclass('BaseActiveMNS', Singleton, object)
22432246

2244-
__metaclass__ = Singleton
2247+
2248+
class ActiveMNS(BaseActiveMNS):
2249+
"""Wrapper class for active module naming scheme."""
22452250

22462251
def __init__(self, *args, **kwargs):
22472252
"""Initialize logger."""

easybuild/framework/easyconfig/tools.py

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -255,17 +255,39 @@ def get_paths_for(subdir=EASYCONFIGS_PKG_SUBDIR, robot_path=None):
255255
path_list.extend(sys.path)
256256

257257
# figure out installation prefix, e.g. distutils install path for easyconfigs
258-
eb_path = which('eb')
258+
259+
# prefer using path specified in $EB_SCRIPT_PATH (if defined), which is set by 'eb' wrapper script
260+
eb_path = os.getenv('EB_SCRIPT_PATH')
261+
if eb_path is None:
262+
# try to determine location of 'eb' script via $PATH, as fallback mechanism
263+
eb_path = which('eb')
264+
_log.info("Location to 'eb' script (found via $PATH): %s", eb_path)
265+
else:
266+
_log.info("Found location to 'eb' script via $EB_SCRIPT_PATH: %s", eb_path)
267+
259268
if eb_path is None:
260269
warning_msg = "'eb' not found in $PATH, failed to determine installation prefix!"
261270
_log.warning(warning_msg)
262271
print_warning(warning_msg)
263272
else:
264-
# real location to 'eb' should be <install_prefix>/bin/eb
265-
eb_path = resolve_path(eb_path)
273+
# eb_path is location to 'eb' wrapper script, e.g. <install_prefix>/bin/eb
274+
# so installation prefix is usually two levels up
266275
install_prefix = os.path.dirname(os.path.dirname(eb_path))
267-
path_list.append(install_prefix)
268-
_log.debug("Also considering installation prefix %s..." % install_prefix)
276+
277+
# only consider resolved path to 'eb' script if desired subdir is not found relative to 'eb' script location
278+
if os.path.exists(os.path.join(install_prefix, 'easybuild', subdir)):
279+
path_list.append(install_prefix)
280+
_log.info("Also considering installation prefix %s (determined via path to 'eb' script)...", install_prefix)
281+
else:
282+
_log.info("Not considering %s (no easybuild/%s subdir found)", install_prefix, subdir)
283+
284+
# also consider fully resolved location to 'eb' wrapper
285+
# see https://github.com/easybuilders/easybuild-framework/pull/2248
286+
resolved_eb_path = resolve_path(eb_path)
287+
if eb_path != resolved_eb_path:
288+
install_prefix = os.path.dirname(os.path.dirname(resolved_eb_path))
289+
path_list.append(install_prefix)
290+
_log.info("Also considering installation prefix %s (via resolved path to 'eb')...", install_prefix)
269291

270292
# look for desired subdirs
271293
for path in path_list:

easybuild/framework/extension.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def __init__(self, mself, ext, extra_params=None):
5757
"""
5858
self.master = mself
5959
self.log = self.master.log
60-
self.cfg = self.master.cfg.copy()
60+
self.cfg = self.master.cfg.copy(validate=False)
6161
self.ext = copy.deepcopy(ext)
6262
self.dry_run = self.master.dry_run
6363

easybuild/framework/extensioneasyblock.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
from easybuild.framework.easyconfig import CUSTOM
3333
from easybuild.framework.extension import Extension
3434
from easybuild.tools.build_log import EasyBuildError
35-
from easybuild.tools.filetools import apply_patch, change_dir, extract_file
35+
from easybuild.tools.filetools import change_dir, extract_file
3636
from easybuild.tools.utilities import remove_unwanted_chars, trace_msg
3737

3838

@@ -88,6 +88,7 @@ def __init__(self, *args, **kwargs):
8888
self.installdir = self.master.installdir
8989
self.modules_tool = self.master.modules_tool
9090
self.module_generator = self.master.module_generator
91+
self.robot_path = self.master.robot_path
9192
self.is_extension = True
9293
self.unpack_options = None
9394
else:
@@ -109,10 +110,7 @@ def run(self, unpack_src=False):
109110
change_dir(self.start_dir)
110111

111112
# patch if needed
112-
if self.patches:
113-
for patchfile in self.patches:
114-
if not apply_patch(patchfile, self.ext_dir):
115-
raise EasyBuildError("Applying patch %s failed", patchfile)
113+
EasyBlock.patch_step(self, beginpath=self.ext_dir)
116114

117115
def sanity_check_step(self, exts_filter=None, custom_paths=None, custom_commands=None):
118116
"""

easybuild/tools/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ def mk_full_default_path(name, prefix=DEFAULT_PREFIX):
227227
'module_only',
228228
'package',
229229
'read_only_installdir',
230+
'remove_ghost_install_dirs',
230231
'rebuild',
231232
'robot',
232233
'rpath',

easybuild/tools/filetools.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -703,7 +703,7 @@ def find_eb_script(script_name):
703703
prev_script_loc = script_loc
704704

705705
# fallback mechanism: check in location relative to location of 'eb'
706-
eb_path = which('eb')
706+
eb_path = os.getenv('EB_SCRIPT_PATH') or which('eb')
707707
if eb_path is None:
708708
_log.warning("'eb' not found in $PATH, failed to determine installation prefix")
709709
else:

0 commit comments

Comments
 (0)