Skip to content

Commit 616abca

Browse files
authored
Merge pull request #3771 from Flamefire/ro-install-dir-fetch
Make logdir writable also when --stop/--fetch is given
2 parents 715f08c + c866662 commit 616abca

File tree

5 files changed

+58
-16
lines changed

5 files changed

+58
-16
lines changed

easybuild/framework/easyblock.py

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3703,15 +3703,21 @@ def build_and_install_one(ecdict, init_env):
37033703

37043704
if os.path.exists(app.installdir) and build_option('read_only_installdir') and (
37053705
build_option('rebuild') or build_option('force')):
3706+
enabled_write_permissions = True
37063707
# re-enable write permissions so we can install additional modules
37073708
adjust_permissions(app.installdir, stat.S_IWUSR, add=True, recursive=True)
3709+
else:
3710+
enabled_write_permissions = False
37083711

37093712
result = app.run_all_steps(run_test_cases=run_test_cases)
37103713

37113714
if not dry_run:
37123715
# also add any extension easyblocks used during the build for reproducibility
37133716
if app.ext_instances:
37143717
copy_easyblocks_for_reprod(app.ext_instances, reprod_dir)
3718+
# If not already done remove the granted write permissions if we did so
3719+
if enabled_write_permissions and os.lstat(app.installdir)[stat.ST_MODE] & stat.S_IWUSR:
3720+
adjust_permissions(app.installdir, stat.S_IWUSR, add=False, recursive=True)
37153721

37163722
except EasyBuildError as err:
37173723
first_n = 300
@@ -3728,28 +3734,37 @@ def build_and_install_one(ecdict, init_env):
37283734

37293735
# successful (non-dry-run) build
37303736
if result and not dry_run:
3737+
def ensure_writable_log_dir(log_dir):
3738+
"""Make sure we can write into the log dir"""
3739+
if build_option('read_only_installdir'):
3740+
# temporarily re-enable write permissions for copying log/easyconfig to install dir
3741+
if os.path.exists(log_dir):
3742+
adjust_permissions(log_dir, stat.S_IWUSR, add=True, recursive=True)
3743+
else:
3744+
parent_dir = os.path.dirname(log_dir)
3745+
if os.path.exists(parent_dir):
3746+
adjust_permissions(parent_dir, stat.S_IWUSR, add=True, recursive=False)
3747+
mkdir(log_dir, parents=True)
3748+
adjust_permissions(parent_dir, stat.S_IWUSR, add=False, recursive=False)
3749+
else:
3750+
mkdir(log_dir, parents=True)
3751+
adjust_permissions(log_dir, stat.S_IWUSR, add=True, recursive=True)
37313752

37323753
if app.cfg['stop']:
37333754
ended = 'STOPPED'
37343755
if app.builddir is not None:
37353756
new_log_dir = os.path.join(app.builddir, config.log_path(ec=app.cfg))
37363757
else:
37373758
new_log_dir = os.path.dirname(app.logfile)
3759+
ensure_writable_log_dir(new_log_dir)
37383760

37393761
# if we're only running the sanity check, we should not copy anything new to the installation directory
37403762
elif build_option('sanity_check_only'):
37413763
_log.info("Only running sanity check, so skipping build stats, easyconfigs archive, reprod files...")
37423764

37433765
else:
37443766
new_log_dir = os.path.join(app.installdir, config.log_path(ec=app.cfg))
3745-
if build_option('read_only_installdir'):
3746-
# temporarily re-enable write permissions for copying log/easyconfig to install dir
3747-
if os.path.exists(new_log_dir):
3748-
adjust_permissions(new_log_dir, stat.S_IWUSR, add=True, recursive=True)
3749-
else:
3750-
adjust_permissions(app.installdir, stat.S_IWUSR, add=True, recursive=False)
3751-
mkdir(new_log_dir, parents=True)
3752-
adjust_permissions(app.installdir, stat.S_IWUSR, add=False, recursive=False)
3767+
ensure_writable_log_dir(new_log_dir)
37533768

37543769
# collect build stats
37553770
_log.info("Collecting build stats...")

easybuild/framework/easyconfig/easyconfig.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,13 @@ def disable_templating(self):
559559
finally:
560560
self.enable_templating = old_enable_templating
561561

562+
def __str__(self):
563+
"""Return a string representation of this EasyConfig instance"""
564+
if self.path:
565+
return '%s EasyConfig @ %s' % (self.name, self.path)
566+
else:
567+
return 'Raw %s EasyConfig' % self.name
568+
562569
def filename(self):
563570
"""Determine correct filename for this easyconfig file."""
564571

easybuild/tools/modules.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -801,7 +801,7 @@ def run_module(self, *args, **kwargs):
801801
else:
802802
args = list(args)
803803

804-
self.log.debug('Current MODULEPATH: %s' % os.environ.get('MODULEPATH', ''))
804+
self.log.debug('Current MODULEPATH: %s' % os.environ.get('MODULEPATH', '<unset>'))
805805

806806
# restore selected original environment variables before running module command
807807
environ = os.environ.copy()

test/framework/toy_build.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -106,21 +106,26 @@ def tearDown(self):
106106
if os.path.exists(self.dummylogfn):
107107
os.remove(self.dummylogfn)
108108

109-
def check_toy(self, installpath, outtxt, version='0.0', versionprefix='', versionsuffix=''):
109+
def check_toy(self, installpath, outtxt, version='0.0', versionprefix='', versionsuffix='', error=None):
110110
"""Check whether toy build succeeded."""
111111

112112
full_version = ''.join([versionprefix, version, versionsuffix])
113113

114+
if error is not None:
115+
error_msg = '\nNote: Caught error: %s' % error
116+
else:
117+
error_msg = ''
118+
114119
# check for success
115-
success = re.compile(r"COMPLETED: Installation ended successfully \(took .* secs?\)")
116-
self.assertTrue(success.search(outtxt), "COMPLETED message found in '%s" % outtxt)
120+
success = re.compile(r"COMPLETED: Installation (ended|STOPPED) successfully \(took .* secs?\)")
121+
self.assertTrue(success.search(outtxt), "COMPLETED message found in '%s'%s" % (outtxt, error_msg))
117122

118123
# if the module exists, it should be fine
119124
toy_module = os.path.join(installpath, 'modules', 'all', 'toy', full_version)
120125
msg = "module for toy build toy/%s found (path %s)" % (full_version, toy_module)
121126
if get_module_syntax() == 'Lua':
122127
toy_module += '.lua'
123-
self.assertTrue(os.path.exists(toy_module), msg)
128+
self.assertTrue(os.path.exists(toy_module), msg + error_msg)
124129

125130
# module file is symlinked according to moduleclass
126131
toy_module_symlink = os.path.join(installpath, 'modules', 'tools', 'toy', full_version)
@@ -183,7 +188,7 @@ def test_toy_build(self, extra_args=None, ec_file=None, tmpdir=None, verify=True
183188
raise myerr
184189

185190
if verify:
186-
self.check_toy(self.test_installpath, outtxt, versionsuffix=versionsuffix)
191+
self.check_toy(self.test_installpath, outtxt, versionsuffix=versionsuffix, error=myerr)
187192

188193
if test_readme:
189194
# make sure postinstallcmds were used
@@ -615,7 +620,16 @@ def test_toy_permissions_installdir(self):
615620
# 2. Existing build with --rebuild -> Reinstall and set read-only
616621
# 3. Existing build with --force -> Reinstall and set read-only
617622
# 4-5: Same as 2-3 but with --skip
618-
for extra_args in ([], ['--rebuild'], ['--force'], ['--skip', '--rebuild'], ['--skip', '--force']):
623+
# 6. Existing build with --fetch -> Test that logs can be written
624+
test_cases = (
625+
[],
626+
['--rebuild'],
627+
['--force'],
628+
['--skip', '--rebuild'],
629+
['--skip', '--force'],
630+
['--rebuild', '--fetch'],
631+
)
632+
for extra_args in test_cases:
619633
self.mock_stdout(True)
620634
self.test_toy_build(ec_file=test_ec, extra_args=['--read-only-installdir'] + extra_args, force=False)
621635
self.mock_stdout(False)

test/framework/utilities.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,13 @@ def eb_main(self, args, do_build=False, return_error=False, logfile=None, verbos
295295
env_before = copy.deepcopy(os.environ)
296296

297297
try:
298-
main(args=args, logfile=logfile, do_build=do_build, testing=testing, modtool=self.modtool)
298+
if '--fetch' in args:
299+
# The config sets modules_tool to None if --fetch is specified,
300+
# so do the same here to keep the behavior consistent
301+
modtool = None
302+
else:
303+
modtool = self.modtool
304+
main(args=args, logfile=logfile, do_build=do_build, testing=testing, modtool=modtool)
299305
except SystemExit as err:
300306
if raise_systemexit:
301307
raise err

0 commit comments

Comments
 (0)