Skip to content

FSL - Improve configuration choice#1498

Merged
boegel merged 9 commits intoeasybuilders:developfrom
vanzod:fsl_choose_config
Sep 20, 2018
Merged

FSL - Improve configuration choice#1498
boegel merged 9 commits intoeasybuilders:developfrom
vanzod:fsl_choose_config

Conversation

@vanzod
Copy link
Copy Markdown
Member

@vanzod vanzod commented Sep 4, 2018

FSL build relies on an internal check and a script to identify the appropriate configuration to use. Since the available configurations are for relatively old compilers, the current easyblock uses difflib.get_close_matches to identify the closest configuration and copies the directory containing it into a new one named after the configuration targeted by FSL. In certain cases the guessed closest configuration is not the same as the one at which required patches are applied, resulting in a build failure.
This easyblock change uses the patch files as first source of information to guess the target directory and rolls back to difflib.get_close_matches only if no target configuration is found in the patches.

Comment thread easybuild/easyblocks/f/fsl.py Outdated

for patch in self.patches:
try:
for line in open(patch['path'], 'r'):
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vanzod Please use the read_file function from filetools

Comment thread easybuild/easyblocks/f/fsl.py Outdated
for patch in self.patches:
try:
for line in open(patch['path'], 'r'):
if all(regex.match(line) for regex in [systype_regex, diff_regex]):
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since there are only two, this is probably clearer:

if systype_regex.match(line) and diff_regex.match(line):

But, is there a specific reason why both regex's can't be joined in a single regex?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason they are separate is because I use systype_regex twice and only once in conjunction with diff_regex. Hence I preferred to split them like that instead of having systype_regex being a subset of diff_regex (i.e. avoid copy/paste).

Comment thread easybuild/easyblocks/f/fsl.py Outdated
try:
for line in open(patch['path'], 'r'):
if all(regex.match(line) for regex in [systype_regex, diff_regex]):
matches = [m.group(0) for l in line.split('/') for m in [systype_regex.search(l)] if m]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, why use a list if you're only considering systype_regex? Ah, because you need a handle for the match (m)... It looks a bit weird like this, probably better roll this out for the sake of clarity:

for part in line.split('/'):
    res = systype_regex.search(part)
    if res:
        patched_cfgs.append(res.group(0))

Comment thread easybuild/easyblocks/f/fsl.py Outdated
matches = [m.group(0) for l in line.split('/') for m in [systype_regex.search(l)] if m]
patched_cfgs.extend(matches)
except OSError, err:
raise EasyBuildError("Unable to open patch file: %s", patch['path'])
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No more need for the the try/except when you use read_file

Comment thread easybuild/easyblocks/f/fsl.py Outdated
# If no patched config is found, pick best guess
cfgdir = os.path.join(self.fsldir, "config")
try:
if not best_cfg:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The try is still relevant here, os.listdir may throw an OSError

Comment thread easybuild/easyblocks/f/fsl.py Outdated

# Prepare config
# Either use patched config or copy closest match
try:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vanzod Please use copy_file or copy_dir below (and then there's no need for the try here

Comment thread easybuild/easyblocks/f/fsl.py Outdated
raise EasyBuildError("Unable to open patch file: %s", patch['path'])

if patched_cfgs:
if patched_cfgs[1:] == patched_cfgs[:-1]:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not check for len(patched_cfgs) == 1?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would work in the first if statement. In the second I am checking that all strings in patched_cfgs are the same, which means that the patch targets only one configuration.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, then please clarify with a comment above this line, that's not clear at all :)

Comment thread easybuild/easyblocks/f/fsl.py Outdated
if patched_cfgs:
if patched_cfgs[1:] == patched_cfgs[:-1]:
best_cfg = patched_cfgs[0]
self.log.debug("Found patched config dir: %s" % (best_cfg))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self.log.debug("...", best_cfg)

Comment thread easybuild/easyblocks/f/fsl.py Outdated
self.log.debug("Found patched config dir: %s" % (best_cfg))
else:
dirs = ', '.join(patched_cfgs)
raise EasyBuildError("Patch files are editing multiple config dirs: %s", dirs)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's OK to pass the raw patched_cfgs in the error message imho

@boegel
Copy link
Copy Markdown
Member

boegel commented Sep 17, 2018

@vanzod I quickly ran into trouble when trying this with an old FSL easyconfig (FSL-4.1.9-goolf-1.4.10.eb):

Patch files are editing multiple config dirs: apple-darwin10-gcc4.2, apple-darwin10-gcc4.2, apple-darwin7-gcc3.1, apple-darwin7-gcc3.1, apple-darwin7-gcc3.3, apple-darwin7-gcc3.3, apple-darwin8-gcc4.0, apple-darwin8-gcc4.0, apple-darwin9-gcc4.0, apple-darwin9-gcc4.0, i686-pc-cygwin-gcc3.2, i686-pc-c

So this will need a version check...

@boegel
Copy link
Copy Markdown
Member

boegel commented Sep 17, 2018

@vanzod It looks like this can only work with FSL 5.0.10 & newer (works with FSL-5.0.10-intel-2017a.eb and FSL-5.0.11-foss-2018b.eb

Comment thread easybuild/easyblocks/f/fsl.py Outdated
cfgs = os.listdir(cfgdir)
best_cfg = difflib.get_close_matches(fslmachtype, cfgs)[0]
self.log.debug("Best matching config dir for %s is %s" % (fslmachtype, best_cfg))
except OSError, err:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SyntaxError: invalid syntax

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be except OSError as err:

Comment thread easybuild/easyblocks/f/fsl.py Outdated
systype_regex = re.compile("^diff.*config\/(.*(apple|gnu|i686|linux|spark)(?:(?!\/).)*)", re.M)

patched_cfgs = []

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blank line contains whitespace

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vanzod The hound is merciless...

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like that

Comment thread easybuild/easyblocks/f/fsl.py Outdated
systype_regex = re.compile("^diff.*config\/(.*(apple|gnu|i686|linux|spark)(?:(?!\/).)*)", re.M)

patched_cfgs = []

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vanzod The hound is merciless...

Comment thread easybuild/easyblocks/f/fsl.py Outdated
cfgs = os.listdir(cfgdir)
best_cfg = difflib.get_close_matches(fslmachtype, cfgs)[0]
self.log.debug("Best matching config dir for %s is %s" % (fslmachtype, best_cfg))
except OSError, err:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be except OSError as err:

Comment thread easybuild/easyblocks/f/fsl.py Outdated
patched_cfgs.extend([i[0] for i in res])

# Check that at least one config has been found
if len(patched_cfgs) != 0:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if patched_cfgs: is fine here

Comment thread easybuild/easyblocks/f/fsl.py Outdated
# Check that at least one config has been found
if len(patched_cfgs) != 0:
# Check that a single config has been patched
if patched_cfgs[1:] == patched_cfgs[:-1]:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vanzod This hurts my brain... How about using nub from vsc.utils.missing and change this to:

if len(nub(patched_cfgs)) == 1:

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like that. I did not know about nub

Comment thread easybuild/easyblocks/f/fsl.py Outdated
best_cfg = difflib.get_close_matches(fslmachtype, cfgs)[0]
self.log.debug("Best matching config dir for %s is %s" % (fslmachtype, best_cfg))
except OSError, err:
raise EasyBuildError("Unable to access configurations directory: %s", err)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

include value of cfgdir in error message please

best_cfg = difflib.get_close_matches(fslmachtype, cfgs)[0]
self.log.debug("Best matching config dir for %s is %s" % (fslmachtype, best_cfg))
except OSError as err:
raise EasyBuildError("Unable to access configuration directory: %s", cfgdir, err)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vanzod You have a %s missing here, this is going to result in a crash rather than an error message, should be:

raise EasyBuildError("Unable to access configuration directory %s: %s", cfgdir, err)

self.log.debug("Copied %s to %s" % (srcdir, tgtdir))
except OSError, err:
raise EasyBuildError("Failed to copy closest matching config dir: %s", err)
if not best_cfg:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm hitting this now:

  File "/tmp/eb-EdQY9x/included-easyblocks/easybuild/easyblocks/fsl.py", line 95, in configure_step
    if not best_cfg:
UnboundLocalError: local variable 'best_cfg' referenced before assignment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like I have accidentally deleted the definition of best_cfg during the refactoring

@boegel boegel added this to the 3.7.0 milestone Sep 18, 2018
Comment thread easybuild/easyblocks/f/fsl.py Outdated

patched_cfgs = []
best_cfg = None

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blank line contains whitespace

Comment thread easybuild/easyblocks/f/fsl.py Outdated
systype_regex = re.compile("^diff.*config\/(.*(apple|gnu|i686|linux|spark)(?:(?!\/).)*)", re.M)

patched_cfgs = []
best_cfg = None
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vanzod This needs to go outside of this if clause to ensure it's always defined for old FSL versions?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True. Sloppy brain

@boegel
Copy link
Copy Markdown
Member

boegel commented Sep 19, 2018

Tests with existing easyconfigs are under way...

raise EasyBuildError("Failed to copy closest matching config dir: %s", err)
if not best_cfg:
cfgs = os.listdir(cfgdir)
best_cfg = difflib.get_close_matches(fslmachtype, cfgs)[0]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vanzod This whole block is now below the if for FSL 5.0.10 or newer, while it wasn't before. That makes this change backward incompatible, resulting in breaking the installation of FSL-5.0.9-intel-2016a.eb for example...

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, no, it's not... But there still seems to be a problem with FSL-5.0.9-intel-2016a.eb (will re-check).

@boegel
Copy link
Copy Markdown
Member

boegel commented Sep 20, 2018

Good to go, thanks @vanzod!

@boegel boegel merged commit b8fbddc into easybuilders:develop Sep 20, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants