-
Notifications
You must be signed in to change notification settings - Fork 305
add conda-lock support to conda easyblock #3397
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
base: develop
Are you sure you want to change the base?
Changes from all commits
25bcd57
2685185
9682388
3c38cd8
b363c0b
68eb020
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -30,13 +30,15 @@ | |
| """ | ||
|
|
||
| import os | ||
| import yaml | ||
|
|
||
|
|
||
| from easybuild.easyblocks.generic.binary import Binary | ||
| from easybuild.framework.easyconfig import CUSTOM | ||
| from easybuild.tools.run import run_cmd | ||
| from easybuild.tools.modules import get_software_root | ||
| from easybuild.tools.build_log import EasyBuildError | ||
|
|
||
| import easybuild.tools.systemtools as st | ||
|
|
||
| class Conda(Binary): | ||
| """Support for installing software using 'conda'.""" | ||
|
|
@@ -50,6 +52,8 @@ def extra_options(extra_vars=None): | |
| 'environment_file': [None, "Conda environment.yml file to use with 'conda env create'", CUSTOM], | ||
| 'remote_environment': [None, "Remote conda environment to use with 'conda env create'", CUSTOM], | ||
| 'requirements': [None, "Requirements specification to pass to 'conda install'", CUSTOM], | ||
| 'use_conda_lock': [False, "Whether to use conda-lock for reproducibility", CUSTOM], | ||
| 'provided_lock_file_name': [None, "Provided lock file name", CUSTOM], | ||
| }) | ||
| return extra_vars | ||
|
|
||
|
|
@@ -62,22 +66,128 @@ def install_step(self): | |
| """Install software using 'conda env create' or 'conda create' & 'conda install' | ||
| (or the 'mamba', etc., equivalent).""" | ||
| if (get_software_root('anaconda2') or get_software_root('miniconda2') or | ||
| get_software_root('anaconda3') or get_software_root('miniconda3') or | ||
| get_software_root('miniforge3')): | ||
| get_software_root('anaconda3') or get_software_root('miniconda3') or get_software_root('miniforge3')): | ||
| conda_cmd = 'conda' | ||
| elif get_software_root('mamba'): | ||
| conda_cmd = 'mamba' | ||
| elif get_software_root('micromamba'): | ||
| conda_cmd = 'micromamba' | ||
| else: | ||
| raise EasyBuildError("No conda/mamba/micromamba available.") | ||
|
|
||
| # initialize conda environment | ||
| # setuptools is just a choice, but *something* needs to be there | ||
| cmd = "%s config --add create_default_packages setuptools" % conda_cmd | ||
| run_cmd(cmd, log_all=True, simple=True) | ||
|
|
||
| if self.cfg['environment_file'] or self.cfg['remote_environment']: | ||
| def get_system_platform_name(): | ||
| system = st.get_system_info()['os_type'].lower() | ||
| machine = st.get_system_info()['cpu_arch'].lower() | ||
|
|
||
| platforms = { | ||
| "linux": { | ||
| "x86_64": "linux-64", | ||
| "aarch64": "linux-aarch64", | ||
| "ppc64le": "linux-ppc64le", | ||
| "s390x": "linux-s390x" | ||
| }, | ||
| "darwin": { | ||
| "x86_64": "osx-64", | ||
| "arm64": "osx-arm64" | ||
| }, | ||
| "windows": { | ||
| "x86_64": "win-64", | ||
| "amd64": "win-64", | ||
| "arm64": "win-arm64", | ||
| "x86": "win-32" | ||
| }, | ||
| "zos": { | ||
| "z": "zos-z" | ||
| } | ||
| } | ||
|
|
||
| return platforms.get(system, {}).get(machine) | ||
|
|
||
| def check_lock_file_type(lock_file): | ||
| _, ext = os.path.splitext(lock_file) | ||
| if ext == ".lock": | ||
| return "single" | ||
| elif ext in [".yml", ".yaml"]: | ||
| return "multi" | ||
| else: | ||
| raise EasyBuildError("The provided file is not a lock file") | ||
|
|
||
| def verify_lock_file_platform(lock_file, platform_name): | ||
|
|
||
| file_type = check_lock_file_type(lock_file) | ||
|
|
||
| if file_type == "multi": | ||
| # for a multi-platform lock file like conda-lock.yml | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. expected an indented block (comment) |
||
| with open(lock_file, 'r') as f: | ||
| lock_data = yaml.safe_load(f) | ||
| return platform_name in lock_data.get('metadata', []).get('platforms',[]) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. missing whitespace after ',' |
||
| else: | ||
| # for a single-platform rendered lock file like conda-linux64.lock | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. expected an indented block (comment) |
||
| with open(lock_file, 'r') as f: | ||
| for line in f: | ||
| if line.startswith("# platform:"): | ||
| return line.split(":", 1)[1].strip() == platform_name | ||
|
|
||
|
|
||
| if self.cfg['use_conda_lock']: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. too many blank lines (2) |
||
| lock_file = self.cfg['provided_lock_file_name'] | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. multiple spaces after operator |
||
| platform_name = get_system_platform_name() | ||
|
|
||
| # the default name for rendered lock_file is 'conda-<platform>.lock' | ||
| platform_rendered_lock_file='conda-{}.lock'.format(platform_name) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. missing whitespace around operator |
||
|
|
||
| if not lock_file: | ||
| # install conda-lock | ||
| cmd = "%s install conda-lock" % conda_cmd | ||
| run_cmd(cmd, log_all=True, simple=True) | ||
|
|
||
| # ship environment file in installation | ||
| super(Binary, self).fetch_sources(sources=[self.cfg['environment_file']]) | ||
| self.extract_step() | ||
|
|
||
| # generate lock file and render | ||
| cmd = "conda-lock -f %s -p %s && conda-lock render -p %s" % ( | ||
| self.cfg['environment_file'], platform_name, platform_name) | ||
| run_cmd(cmd, log_all=True, simple=True) | ||
|
|
||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. blank line contains whitespace |
||
| else: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. too many blank lines (2) |
||
|
|
||
| lock_file_type = check_lock_file_type(lock_file) | ||
|
|
||
| # ship lock_file in installation | ||
| super(Binary, self).fetch_sources(sources=[lock_file]) | ||
| self.extract_step() | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. blank line contains whitespace |
||
| # verify that a lock file for the current platform has been provided | ||
| if not verify_lock_file_platform(lock_file,platform_name): | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. missing whitespace after ',' |
||
| raise EasyBuildError("The provided lock file does not match this platform") | ||
|
|
||
|
|
||
| if lock_file_type == "multi": | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. too many blank lines (2) |
||
|
|
||
| # install conda-lock | ||
| cmd = "%s install conda-lock" % conda_cmd | ||
| run_cmd(cmd, log_all=True, simple=True) | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. blank line contains whitespace |
||
| # render | ||
| cmd = "conda-lock render -p %s %s" % (platform_name, lock_file) | ||
| run_cmd(cmd, log_all=True, simple=True) | ||
| else: | ||
|
|
||
| platform_rendered_lock_file=lock_file | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. missing whitespace around operator |
||
|
|
||
|
|
||
| # use lock_file to create environment | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. too many blank lines (2) |
||
| cmd = "%s %s create --file %s -p %s -y" % (self.cfg['preinstallopts'],conda_cmd, platform_rendered_lock_file, self.installdir) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. line too long (138 > 120 characters) |
||
| run_cmd(cmd, log_all=True, simple=True) | ||
|
|
||
| elif self.cfg['environment_file'] or self.cfg['remote_environment']: | ||
|
|
||
| if self.cfg['environment_file']: | ||
| env_spec = '-f ' + self.cfg['environment_file'] | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
blank line contains whitespace