-
Notifications
You must be signed in to change notification settings - Fork 217
add (experimental) support for specifying easyconfig files via "easystack" file #3479
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
boegel
merged 82 commits into
easybuilders:develop
from
deniskristak:feature/build-from-specsfile
Nov 30, 2020
Merged
Changes from all commits
Commits
Show all changes
82 commits
Select commit
Hold shift + click to select a range
78b482a
building eb commands added to eb framework
deniskristak f0a7c61
format changes
deniskristak 3180d78
format changes
deniskristak 9ac800b
beautified
deniskristak d78923b
pep8 repairs & class reorganisation
deniskristak 2e5f2ab
format changes
deniskristak 1cd2b3a
input validation
deniskristak de8049b
passed easyconfigs as arguments inside of main
deniskristak 28e7fde
added test skeleton
deniskristak cfe38af
test
deniskristak b0ddf19
format tweaks
deniskristak 7075c31
added Wrong structure test
deniskristak e4230c4
small stuff
deniskristak 9d13d1d
test success - WIP
deniskristak 364699d
WIP success test
deniskristak 9e240c1
wip: testing success
deniskristak e62a4ea
specsfile pouziva dobre ec
deniskristak 00ebd3c
test
deniskristak eb8dce2
test
1de3e4a
test
deniskristak e6f7452
test
deniskristak f659426
test
24b53eb
Merge pull request #1 from deniskristak/feature/specsfile-private
deniskristak 58c5d7d
cosmetic changes
deniskristak 4f83aac
Merge pull request #2 from deniskristak/feature/specsfile-private
deniskristak d61d078
format changes
deniskristak 8435b5f
cosmetic changes
c6ad30e
test
feec790
test
deniskristak 2a8dcf2
test
deniskristak fd01052
test
be5bf5c
Merge pull request #3 from deniskristak/feature/specsfile-devel
deniskristak 36117c5
rename to easystack
deniskristak 840c7bf
Merge branch 'feature/specsfile-devel' of https://github.com/deniskri…
64879f5
test
deniskristak 0543275
test
82bedcb
Merge pull request #4 from deniskristak/feature/specsfile-devel
deniskristak 2ed5b0d
tests
deniskristak 768a512
tests
deniskristak b7e3ac5
test
deniskristak dfc2d91
added tests, cleaned up
49a7535
Merge pull request #5 from deniskristak/easystack-devel
deniskristak c7a88fb
test
db9a127
tests
2a8485d
tests
da2b46b
experimental set
41e5ce9
tests
3aff446
tests
f78c411
tests
92dd35e
tests
f9081e4
tests
9ec4eb5
tests
9747f16
Delete test_result.log
deniskristak 844523d
tests
ee685d6
Merge branch 'feature/build-from-specsfile' of https://github.com/den…
45d0a22
tests
42c0953
tests
f29da8e
tests
8ca3e3e
tests
311b2c3
tests
add91c8
tests
97343a1
tests
e3b3c82
more adequate naming
79739ae
changes based on the latest review
05e2d86
changes based on comments
7e1c984
tests
8d036e4
tests
0073e4d
tests
2b9fa56
tests
6e7497e
tests
a73787a
tests
913695f
tests
b5a5ab6
tests
823925f
tests
ccf8c4d
tests
390e7ab
tests
7c24a46
tests
f60a0c6
changes after review
deniskristak de1a4c0
linting
deniskristak e6c5d9c
make only_if_module_is_available produce slightly better error message
boegel 1cd9131
only run EasyStackParser.parse if PyYAML is installed
boegel f584f53
tweak error messages produces for easystack files + reformat how Soft…
boegel File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,234 @@ | ||
| # Copyright 2020-2020 Ghent University | ||
| # | ||
| # This file is part of EasyBuild, | ||
| # originally created by the HPC team of Ghent University (http://ugent.be/hpc/en), | ||
| # with support of Ghent University (http://ugent.be/hpc), | ||
| # the Flemish Supercomputer Centre (VSC) (https://www.vscentrum.be), | ||
| # Flemish Research Foundation (FWO) (http://www.fwo.be/en) | ||
| # and the Department of Economy, Science and Innovation (EWI) (http://www.ewi-vlaanderen.be/en). | ||
| # | ||
| # https://github.com/easybuilders/easybuild | ||
| # | ||
| # EasyBuild is free software: you can redistribute it and/or modify | ||
| # it under the terms of the GNU General Public License as published by | ||
| # the Free Software Foundation v2. | ||
| # | ||
| # EasyBuild is distributed in the hope that it will be useful, | ||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| # GNU General Public License for more details. | ||
| # | ||
| # You should have received a copy of the GNU General Public License | ||
| # along with EasyBuild. If not, see <http://www.gnu.org/licenses/>. | ||
| # | ||
| """ | ||
| Support for easybuild-ing from multiple easyconfigs based on | ||
| information obtained from provided file (easystack) with build specifications. | ||
|
|
||
| :author: Denis Kristak (Inuits) | ||
| :author: Pavel Grochal (Inuits) | ||
| """ | ||
|
|
||
| from easybuild.base import fancylogger | ||
| from easybuild.tools.build_log import EasyBuildError | ||
| from easybuild.tools.filetools import read_file | ||
| from easybuild.tools.module_naming_scheme.utilities import det_full_ec_version | ||
| from easybuild.tools.utilities import only_if_module_is_available | ||
| try: | ||
| import yaml | ||
| except ImportError: | ||
| pass | ||
| _log = fancylogger.getLogger('easystack', fname=False) | ||
|
|
||
|
|
||
| class EasyStack(object): | ||
| """One class instance per easystack. General options + list of all SoftwareSpecs instances""" | ||
|
|
||
| def __init__(self): | ||
| self.easybuild_version = None | ||
| self.robot = False | ||
| self.software_list = [] | ||
|
|
||
| def compose_ec_filenames(self): | ||
| """Returns a list of all easyconfig names""" | ||
| ec_filenames = [] | ||
| for sw in self.software_list: | ||
| full_ec_version = det_full_ec_version({ | ||
| 'toolchain': {'name': sw.toolchain_name, 'version': sw.toolchain_version}, | ||
| 'version': sw.version, | ||
| 'versionsuffix': sw.versionsuffix, | ||
| }) | ||
| ec_filename = '%s-%s.eb' % (sw.name, full_ec_version) | ||
| ec_filenames.append(ec_filename) | ||
| return ec_filenames | ||
|
|
||
| # flags applicable to all sw (i.e. robot) | ||
| def get_general_options(self): | ||
| """Returns general options (flags applicable to all sw (i.e. --robot))""" | ||
| general_options = {} | ||
| # TODO add support for general_options | ||
| # general_options['robot'] = self.robot | ||
| # general_options['easybuild_version'] = self.easybuild_version | ||
| return general_options | ||
|
|
||
|
|
||
| class SoftwareSpecs(object): | ||
| """Contains information about every software that should be installed""" | ||
|
|
||
| def __init__(self, name, version, versionsuffix, toolchain_version, toolchain_name): | ||
| self.name = name | ||
| self.version = version | ||
| self.toolchain_version = toolchain_version | ||
| self.toolchain_name = toolchain_name | ||
| self.versionsuffix = versionsuffix | ||
|
|
||
|
|
||
| class EasyStackParser(object): | ||
| """Parser for easystack files (in YAML syntax).""" | ||
|
|
||
| @only_if_module_is_available('yaml', pkgname='PyYAML') | ||
| @staticmethod | ||
| def parse(filepath): | ||
| """Parses YAML file and assigns obtained values to SW config instances as well as general config instance""" | ||
| yaml_txt = read_file(filepath) | ||
| easystack_raw = yaml.safe_load(yaml_txt) | ||
| easystack = EasyStack() | ||
|
|
||
| try: | ||
deniskristak marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| software = easystack_raw["software"] | ||
| except KeyError: | ||
| wrong_structure_file = "Not a valid EasyStack YAML file: no 'software' key found" | ||
| raise EasyBuildError(wrong_structure_file) | ||
|
|
||
| # assign software-specific easystack attributes | ||
| for name in software: | ||
| # ensure we have a string value (YAML parser returns type = dict | ||
| # if levels under the current attribute are present) | ||
| name = str(name) | ||
boegel marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| try: | ||
| toolchains = software[name]['toolchains'] | ||
| except KeyError: | ||
| raise EasyBuildError("Toolchains for software '%s' are not defined in %s", name, filepath) | ||
| for toolchain in toolchains: | ||
| toolchain = str(toolchain) | ||
| toolchain_parts = toolchain.split('-', 1) | ||
| if len(toolchain_parts) == 2: | ||
| toolchain_name, toolchain_version = toolchain_parts | ||
| elif len(toolchain_parts) == 1: | ||
| toolchain_name, toolchain_version = toolchain, '' | ||
| else: | ||
| raise EasyBuildError("Incorrect toolchain specification for '%s' in %s, too many parts: %s", | ||
| name, filepath, toolchain_parts) | ||
|
|
||
| try: | ||
| # if version string containts asterisk or labels, raise error (asterisks not supported) | ||
| versions = toolchains[toolchain]['versions'] | ||
| except TypeError as err: | ||
| wrong_structure_err = "An error occurred when interpreting " | ||
| wrong_structure_err += "the data for software %s: %s" % (name, err) | ||
| raise EasyBuildError(wrong_structure_err) | ||
| if '*' in str(versions): | ||
| asterisk_err = "EasyStack specifications of '%s' in %s contain asterisk. " | ||
| asterisk_err += "Wildcard feature is not supported yet." | ||
| raise EasyBuildError(asterisk_err, name, filepath) | ||
|
|
||
| # yaml versions can be in different formats in yaml file | ||
| # firstly, check if versions in yaml file are read as a dictionary. | ||
| # Example of yaml structure: | ||
| # ======================================================================== | ||
| # versions: | ||
| # 2.25: | ||
| # 2.23: | ||
| # versionsuffix: '-R-4.0.0' | ||
| # ======================================================================== | ||
| if isinstance(versions, dict): | ||
| for version in versions: | ||
| if versions[version] is not None: | ||
| version_spec = versions[version] | ||
| if 'versionsuffix' in version_spec: | ||
| versionsuffix = str(version_spec['versionsuffix']) | ||
| else: | ||
| versionsuffix = '' | ||
| if 'exclude-labels' in str(version_spec) or 'include-labels' in str(version_spec): | ||
| lab_err = "EasyStack specifications of '%s' in %s " | ||
| lab_err += "contain labels. Labels aren't supported yet." | ||
| raise EasyBuildError(lab_err, name, filepath) | ||
| else: | ||
| versionsuffix = '' | ||
|
|
||
| specs = { | ||
| 'name': name, | ||
| 'toolchain_name': toolchain_name, | ||
| 'toolchain_version': toolchain_version, | ||
| 'version': version, | ||
| 'versionsuffix': versionsuffix, | ||
| } | ||
| sw = SoftwareSpecs(**specs) | ||
|
|
||
| # append newly created class instance to the list in instance of EasyStack class | ||
| easystack.software_list.append(sw) | ||
| continue | ||
|
|
||
| # is format read as a list of versions? | ||
| # ======================================================================== | ||
| # versions: | ||
| # [2.24, 2.51] | ||
| # ======================================================================== | ||
| elif isinstance(versions, list): | ||
| versions_list = versions | ||
|
|
||
| # format = multiple lines without ':' (read as a string)? | ||
| # ======================================================================== | ||
| # versions: | ||
| # 2.24 | ||
| # 2.51 | ||
| # ======================================================================== | ||
| elif isinstance(versions, str): | ||
| versions_list = str(versions).split() | ||
|
|
||
| # format read as float (containing one version only)? | ||
| # ======================================================================== | ||
| # versions: | ||
| # 2.24 | ||
| # ======================================================================== | ||
| elif isinstance(versions, float): | ||
| versions_list = [str(versions)] | ||
|
|
||
| # if no version is a dictionary, versionsuffix isn't specified | ||
| versionsuffix = '' | ||
|
|
||
| for version in versions_list: | ||
| sw = SoftwareSpecs( | ||
| name=name, version=version, versionsuffix=versionsuffix, | ||
| toolchain_name=toolchain_name, toolchain_version=toolchain_version) | ||
| # append newly created class instance to the list in instance of EasyStack class | ||
| easystack.software_list.append(sw) | ||
|
|
||
| # assign general easystack attributes | ||
| easystack.easybuild_version = easystack_raw.get('easybuild_version', None) | ||
| easystack.robot = easystack_raw.get('robot', False) | ||
|
|
||
| return easystack | ||
|
|
||
|
|
||
| def parse_easystack(filepath): | ||
| """Parses through easystack file, returns what EC are to be installed together with their options.""" | ||
| log_msg = "Support for easybuild-ing from multiple easyconfigs based on " | ||
| log_msg += "information obtained from provided file (easystack) with build specifications." | ||
| _log.experimental(log_msg) | ||
| _log.info("Building from easystack: '%s'" % filepath) | ||
|
|
||
| # class instance which contains all info about planned build | ||
| easystack = EasyStackParser.parse(filepath) | ||
|
|
||
| easyconfig_names = easystack.compose_ec_filenames() | ||
|
|
||
| general_options = easystack.get_general_options() | ||
|
|
||
| _log.debug("EasyStack parsed. Proceeding to install these Easyconfigs: \n'%s'" % "',\n'".join(easyconfig_names)) | ||
| if len(general_options) != 0: | ||
| _log.debug("General options for installation are: \n%s" % str(general_options)) | ||
| else: | ||
| _log.debug("No general options were specified in easystack") | ||
|
|
||
| return easyconfig_names, general_options | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| software: | ||
| binutils: | ||
| toolchains: | ||
| GCCcore-4.9.3: | ||
| versions: | ||
| "2.11.*" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| software: | ||
| binutils: | ||
| toolchains: | ||
| GCCcore-4.9.3: | ||
| versions: | ||
| 2.25: | ||
| 2.26: | ||
| toy: | ||
| toolchains: | ||
| gompi-2018a: | ||
| versions: | ||
| 0.0: | ||
| versionsuffix: '-test' |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| software: | ||
| binutils: | ||
| toolchains: | ||
| GCCcore-4.9.3: | ||
| versions: | ||
| 3.11: | ||
| exclude-labels: arch:aarch64 |
6 changes: 6 additions & 0 deletions
6
test/framework/easystacks/test_easystack_wrong_structure.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| software: | ||
| Bioconductor: | ||
| toolchains: | ||
| # foss-2020a: | ||
| versions: | ||
| 3.11 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.