FSL - Improve configuration choice#1498
Conversation
|
|
||
| for patch in self.patches: | ||
| try: | ||
| for line in open(patch['path'], 'r'): |
There was a problem hiding this comment.
@vanzod Please use the read_file function from filetools
| 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]): |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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).
| 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] |
There was a problem hiding this comment.
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))| 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']) |
There was a problem hiding this comment.
No more need for the the try/except when you use read_file
| # If no patched config is found, pick best guess | ||
| cfgdir = os.path.join(self.fsldir, "config") | ||
| try: | ||
| if not best_cfg: |
There was a problem hiding this comment.
The try is still relevant here, os.listdir may throw an OSError
|
|
||
| # Prepare config | ||
| # Either use patched config or copy closest match | ||
| try: |
There was a problem hiding this comment.
@vanzod Please use copy_file or copy_dir below (and then there's no need for the try here
| raise EasyBuildError("Unable to open patch file: %s", patch['path']) | ||
|
|
||
| if patched_cfgs: | ||
| if patched_cfgs[1:] == patched_cfgs[:-1]: |
There was a problem hiding this comment.
Why not check for len(patched_cfgs) == 1?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
OK, then please clarify with a comment above this line, that's not clear at all :)
| 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)) |
| 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) |
There was a problem hiding this comment.
it's OK to pass the raw patched_cfgs in the error message imho
|
@vanzod I quickly ran into trouble when trying this with an old FSL easyconfig ( So this will need a version check... |
|
@vanzod It looks like this can only work with FSL 5.0.10 & newer (works with |
| 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: |
There was a problem hiding this comment.
This should probably be except OSError as err:
| systype_regex = re.compile("^diff.*config\/(.*(apple|gnu|i686|linux|spark)(?:(?!\/).)*)", re.M) | ||
|
|
||
| patched_cfgs = [] | ||
|
|
| systype_regex = re.compile("^diff.*config\/(.*(apple|gnu|i686|linux|spark)(?:(?!\/).)*)", re.M) | ||
|
|
||
| patched_cfgs = [] | ||
|
|
| 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: |
There was a problem hiding this comment.
This should probably be except OSError as err:
| patched_cfgs.extend([i[0] for i in res]) | ||
|
|
||
| # Check that at least one config has been found | ||
| if len(patched_cfgs) != 0: |
| # 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]: |
There was a problem hiding this comment.
@vanzod This hurts my brain... How about using nub from vsc.utils.missing and change this to:
if len(nub(patched_cfgs)) == 1:There was a problem hiding this comment.
I like that. I did not know about nub
| 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) |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
@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: |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
It looks like I have accidentally deleted the definition of best_cfg during the refactoring
|
|
||
| patched_cfgs = [] | ||
| best_cfg = None | ||
|
|
| systype_regex = re.compile("^diff.*config\/(.*(apple|gnu|i686|linux|spark)(?:(?!\/).)*)", re.M) | ||
|
|
||
| patched_cfgs = [] | ||
| best_cfg = None |
There was a problem hiding this comment.
@vanzod This needs to go outside of this if clause to ensure it's always defined for old FSL versions?
|
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] |
There was a problem hiding this comment.
@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...
There was a problem hiding this comment.
Wait, no, it's not... But there still seems to be a problem with FSL-5.0.9-intel-2016a.eb (will re-check).
|
Good to go, thanks @vanzod! |
FSLbuild 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 usesdifflib.get_close_matchesto identify the closest configuration and copies the directory containing it into a new one named after the configuration targeted byFSL. 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_matchesonly if no target configuration is found in the patches.