Skip to content
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

Added mamba support #22

Merged
merged 10 commits into from
Nov 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,15 @@ jobs:
with:
path: ${{ env.BAZEL_CACHE_DIR }}
key: ${{ runner.os }}-bazel-${{ env.CACHE_NUMBER }}
- name: Run miniconda tests
working-directory: tests/miniconda
- name: Test miniconda with conda
working-directory: tests/miniconda/conda
run: bazel test --test_output=all --test_arg=--verbose --test_arg=-rA ...
- name: Run miniforge tests
working-directory: tests/miniforge
- name: Test miniconda with mamba
working-directory: tests/miniconda/mamba
run: bazel test --test_output=all --test_arg=--verbose --test_arg=-rA ...
- name: Test miniforge with conda
working-directory: tests/miniforge/conda
run: bazel test --test_output=all --test_arg=--verbose --test_arg=-rA ...
- name: Test miniforge with mamba
working-directory: tests/miniforge/mamba
run: bazel test --test_output=all --test_arg=--verbose --test_arg=-rA ...
32 changes: 27 additions & 5 deletions conda.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,21 @@ def _install_conda(rctx, installer):
fail("Failure installing conda.\nstdout: {}\nstderr: {}".format(result.stdout, result.stderr))
return "{}/condabin/conda{}".format(rctx.attr.conda_dir, CONDA_EXT_MAP[os])

def _install_mamba(rctx, executable):
rctx.report_progress("Installing mamba")
mamba_with_version = "mamba={}".format(rctx.attr.mamba_version)

# `-n base` is necessary so that mamba is installed to the conda in the bazel cache.
# If we omit `-n base`, then mamba can get installed to the user's environment i.e. ~/anaconda3 which breaks
# the hermetic nature of the build.
args = [rctx.path(executable), "install", "-n", "base", "-c", "conda-forge", mamba_with_version, "-y"]
GabrielDougherty marked this conversation as resolved.
Show resolved Hide resolved
result = rctx.execute(args, quiet = rctx.attr.quiet, working_directory = rctx.attr.conda_dir, timeout = rctx.attr.timeout)
if result.return_code:
fail("Failure when installing mamba.\nstdout: {}\nstderr: {}".format(result.stdout, result.stderr))

# use conda to update itself
def _update_conda(rctx, executable):
conda_with_version = "conda={}".format(rctx.attr.version)
conda_with_version = "conda={}".format(rctx.attr.conda_version)
args = [rctx.path(executable), "install", conda_with_version, "-y"]

# update conda itself
Expand All @@ -130,22 +142,32 @@ def _create_conda_build_file(rctx, executable):

def _load_conda_impl(rctx):
installer = _download_conda(rctx)
executable = _install_conda(rctx, installer)
_update_conda(rctx, executable)
_create_conda_build_file(rctx, executable)
conda_executable = _install_conda(rctx, installer)
_update_conda(rctx, conda_executable)
if rctx.attr.install_mamba:
_install_mamba(rctx, conda_executable)
_create_conda_build_file(rctx, conda_executable)

load_conda_rule = repository_rule(
_load_conda_impl,
attrs = {
"conda_dir": attr.string(mandatory = True),
"version": attr.string(
"conda_version": attr.string(
mandatory = True,
doc = "Conda version to install",
),
"installer": attr.string(
default = "miniconda",
doc = 'Installer to use, either "miniconda" or "miniforge". Note that miniconda and miniforge have different OS/arch support.',
),
"install_mamba": attr.bool(
default = False,
doc = "False if mamba should not be installed",
),
"mamba_version": attr.string(
mandatory = True,
doc = "Mamba version to install",
),
"quiet": attr.bool(
default = True,
doc = "False if conda output should be shown",
Expand Down
6 changes: 4 additions & 2 deletions defs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@ DEFAULT_CONDA_VERSION = "4.10.3"
DEFAULT_ENV_NAME = "my_env"
DEFAULT_TOOLCHAIN_REPO_NAME = "conda_tools"
DEFAULT_TOOLCHAIN_NAME = "python_toolchain"
DEFAULT_MAMBA_VERSION = "0.17.0"

# download and install conda
def load_conda(version = DEFAULT_CONDA_VERSION, **kwargs):
def load_conda(conda_version = DEFAULT_CONDA_VERSION, mamba_version = DEFAULT_MAMBA_VERSION, **kwargs):
maybe(
load_conda_rule,
CONDA_REPO_NAME,
conda_dir = CONDA_DIR,
version = version,
conda_version = conda_version,
mamba_version = mamba_version,
**kwargs
)

Expand Down
29 changes: 16 additions & 13 deletions docs/docs/usage/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@

**Parameters:**

| Name | Description | Default |
| ------------- | ------------------------------------------------------------------------------------------ | ---------------------- |
| `installer` | Which `conda` installer to download, either `miniconda` or `miniforge` | `miniconda` |
| `version` | Version of `conda` to download | `4.10.3` |
| `quiet` | `True` if `conda` output should be hidden | `True` |
| `timeout` | How many seconds each execute action can take | `3600` |
| Name | Description | Default |
| --------------- | ------------------------------------------------------------------------------------------ | ---------------------- |
| `conda_version` | Version of `conda` to download | `4.10.3` |
| `installer` | Which `conda` installer to download, either `miniconda` or `miniforge` | `miniconda` |
| `install_mamba` | Whether to install `mamba`, which is a faster drop-in replacement for `conda` | `False` |
| `mamba_version` | Version of `conda` to install | `0.17.0` |
| `quiet` | `True` if `conda` output should be hidden | `True` |
| `timeout` | How many seconds each execute action can take | `3600` |

## `conda_create`

Expand All @@ -23,13 +25,14 @@

**Parameters:**

| Name | Description | Default |
| ------------- | ------------------------------------------------------------------------------------------ | ---------------------- |
| `environment` | label pointing to environment configuration file (typically named `environment.yml`) | |
| `name` | Name of the environment | `my_env` |
| `quiet` | `True` if `conda` output should be hidden | `True` |
| `timeout` | How many seconds each execute action can take | `3600` |
| `clean` | `True` if `conda` cache should be cleaned (less space taken, but slower subsequent builds) | `False` |
| Name | Description | Default |
| ------------- | ---------------------------------------------------------------------------------------------------------------- | ---------------------- |
| `environment` | label pointing to environment configuration file (typically named `environment.yml`) | |
| `name` | Name of the environment | `my_env` |
| `quiet` | `True` if `conda` output should be hidden | `True` |
| `timeout` | How many seconds each execute action can take | `3600` |
| `clean` | `True` if `conda` cache should be cleaned (less space taken, but slower subsequent builds) | `False` |
| `use_mamba` | Whether to use `mamba` to create the `conda` environment. If this is `True`, `install_mamba` must also be `True` | `False` |

## `register_toolchain`

Expand Down
2 changes: 2 additions & 0 deletions docs/docs/usage/example.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ load_conda(
installer = "miniconda", # "miniconda" or "miniforge", defaults to "miniconda"
quiet = False, # use True to hide conda output
version = "4.10.3", # optional, defaults to 4.10.3
GabrielDougherty marked this conversation as resolved.
Show resolved Hide resolved
install_mamba = False, # use True to use mamba, which a faster drop-in replacement for conda
)

conda_create(
Expand All @@ -41,6 +42,7 @@ conda_create(
clean = False, # use True if you want to clean conda cache (less space taken, but slower subsequent builds)
environment = "@//:environment.yml", # label pointing to environment.yml file
quiet = False, # use True to hide conda output
use_mamba = False, # use True to use mamba, which a faster drop-in replacement for conda
)

register_toolchain(
Expand Down
45 changes: 36 additions & 9 deletions env.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,52 @@ py_runtime(
)
"""

def _label_from_condabin(rctx, exe_name):
return Label("@{}//:{}/condabin/{}{}".format(
rctx.attr.conda_repo,
rctx.attr.conda_dir,
exe_name,
CONDA_EXT_MAP[get_os(rctx)],
))

def _user_chosen_executable(rctx):
if rctx.attr.use_mamba:
return _label_from_condabin(rctx, "mamba")
return _label_from_condabin(rctx, "conda")

# clean conda caches and unused packages
def _clean(rctx, executable):
rctx.report_progress("Cleaning up")

args = [rctx.path(executable), "clean", "-a", "-y"]
args = [executable, "clean", "-a", "-y"]

result = rctx.execute(args, quiet = rctx.attr.quiet, timeout = rctx.attr.timeout)
if result.return_code:
fail("Failure cleaning up.\nstdout: {}\nstderr: {}".format(result.stdout, result.stderr))

def _create_empty_environment(rctx, executable, env_name):
rctx.report_progress("Creating empty conda environment, to be populated afterwards")
args = [executable, "create", "-y", "-p", "./{}".format(env_name)]
result = rctx.execute(args, quiet = rctx.attr.quiet, timeout = rctx.attr.timeout)
if result.return_code:
fail("Failure creating empty environment.\nstdout: {}\nstderr: {}".format(result.stdout, result.stderr))

def _update_environment(rctx, executable, env_name, env_file):
rctx.report_progress("Updating empty conda environment to populate it")
args = [executable, "env", "update", "-f", env_file, "-p", "./{}".format(env_name)]
result = rctx.execute(args, quiet = rctx.attr.quiet, timeout = rctx.attr.timeout)
if result.return_code:
fail("Failure updating environment.\nstdout: {}\nstderr: {}".format(result.stdout, result.stderr))

# create new local conda environment from file
def _create_environment(rctx, executable, env_name):
rctx.report_progress("Creating conda environment")

# path to env file as string
env_file = str(rctx.path(rctx.attr.environment))

args = [rctx.path(executable), "env", "create", "-f", env_file, "-p", "./{}".format(env_name)]
env_file = rctx.path(rctx.attr.environment)

result = rctx.execute(args, quiet = rctx.attr.quiet, timeout = rctx.attr.timeout)
if result.return_code:
fail("Failure creating environment.\nstdout: {}\nstderr: {}".format(result.stdout, result.stderr))
_create_empty_environment(rctx, executable, env_name)
_update_environment(rctx, executable, env_name, env_file)

# check if python2 or python3 has been installed
def _get_py_major(rctx, env_path, interpreter_path):
Expand All @@ -59,8 +83,7 @@ def _create_env_build_file(rctx, env_name):
)

def _conda_create_impl(rctx):
conda_label = Label("@{}//:{}/condabin/conda{}".format(rctx.attr.conda_repo, rctx.attr.conda_dir, CONDA_EXT_MAP[get_os(rctx)]))
executable = str(rctx.path(conda_label))
executable = _user_chosen_executable(rctx)
env_name = rctx.name
_create_environment(rctx, executable, env_name)
if rctx.attr.clean:
Expand All @@ -81,6 +104,10 @@ conda_create_rule = repository_rule(
default = True,
doc = "False if conda output should be shown",
),
"use_mamba": attr.bool(
default = False,
doc = "True if mamba should be used",
),
"timeout": attr.int(
default = EXECUTE_TIMEOUT,
doc = "Timeout in seconds for each execute action",
Expand Down
6 changes: 5 additions & 1 deletion example/WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,10 @@ load("@rules_conda//:defs.bzl", "conda_create", "load_conda", "register_toolchai

# download and install conda
load_conda(
conda_version = "4.10.3", # optional, defaults to 4.10.3
install_mamba = False, # use True to install mamba, which a faster drop-in replacement for conda
mamba_version = "0.17.0", # optional, defaults to 0.17.0
quiet = False, # use True to hide conda output
version = "4.10.3", # optional, defaults to 4.10.3
)

# create environment with python2
Expand All @@ -73,6 +75,7 @@ conda_create(
clean = False, # use True if you want to clean conda cache (less space taken, but slower subsequent builds)
environment = "@//third_party/conda:py2_environment.yml", # label pointing to environment.yml file
quiet = False, # use True to hide conda output
use_mamba = False, # use True to use mamba, which a faster drop-in replacement for conda
)

# create environment with python3
Expand All @@ -82,6 +85,7 @@ conda_create(
clean = False, # use True if you want to clean conda cache (less space taken, but slower subsequent builds)
environment = "@//third_party/conda:py3_environment.yml", # label pointing to environment.yml file
quiet = False, # use True to hide conda output
use_mamba = False, # use True to use mamba, which a faster drop-in replacement for conda
)

# register pythons from environment as toolchain
Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ http_archive(

local_repository(
name = "rules_conda",
path = "../../",
path = "../../../",
)

load("@rules_conda//:defs.bzl", "conda_create", "load_conda", "register_toolchain")
Expand Down
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions tests/miniconda/mamba/.bazeliskrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
USE_BAZEL_VERSION=4.2.1
File renamed without changes.
49 changes: 49 additions & 0 deletions tests/miniconda/mamba/WORKSPACE
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

RULES_PYTHON_NAME = "rules_python"

RULES_PYTHON_TAG = "0.4.0"

RULES_PYTHON_SHA = "954aa89b491be4a083304a2cb838019c8b8c3720a7abb9c4cb81ac7a24230cea"

RULES_PYTHON_REPO = "bazelbuild"

RULES_PYTHON_ARCHIVE = "tar.gz"

RULES_PYTHON_URL = "https://github.com/{repo}/{name}/releases/download/{tag}/{name}-{tag}.{archive}".format(
name = RULES_PYTHON_NAME,
archive = RULES_PYTHON_ARCHIVE,
repo = RULES_PYTHON_REPO,
tag = RULES_PYTHON_TAG,
)

http_archive(
name = RULES_PYTHON_NAME,
sha256 = RULES_PYTHON_SHA,
url = RULES_PYTHON_URL,
)

local_repository(
name = "rules_conda",
path = "../../../",
)

load("@rules_conda//:defs.bzl", "conda_create", "load_conda", "register_toolchain")

load_conda(
install_mamba = True,
quiet = False,
)

conda_create(
name = "test_env",
timeout = 600,
clean = False,
environment = "@//:environment.yml",
quiet = False,
use_mamba = True,
)

register_toolchain(
py3_env = "test_env",
)
File renamed without changes.
File renamed without changes.
7 changes: 7 additions & 0 deletions tests/miniforge/conda/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
load("@rules_python//python:defs.bzl", "py_test")

py_test(
name = "test",
size = "small",
srcs = ["test.py"],
)
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ http_archive(

local_repository(
name = "rules_conda",
path = "../../",
path = "../../../",
)

load("@rules_conda//:defs.bzl", "conda_create", "load_conda", "register_toolchain")
Expand Down
6 changes: 6 additions & 0 deletions tests/miniforge/conda/environment.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
channels:
- default
- conda-forge
dependencies:
- python==3.9.7
- pytest==6.2.4
11 changes: 11 additions & 0 deletions tests/miniforge/conda/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import sys

import pytest


def test_correct_pytest_version():
assert pytest.__version__ == "6.2.4"


if __name__ == "__main__":
sys.exit(pytest.main([__file__] + sys.argv[1:]))
7 changes: 7 additions & 0 deletions tests/miniforge/mamba/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
load("@rules_python//python:defs.bzl", "py_test")

py_test(
name = "test",
size = "small",
srcs = ["test.py"],
)
Loading