diff --git a/conda-store-server/conda_store_server/_internal/plugins/lock/conda_lock/conda_lock.py b/conda-store-server/conda_store_server/_internal/plugins/lock/conda_lock/conda_lock.py index a9d222121..a4fb35c0a 100644 --- a/conda-store-server/conda_store_server/_internal/plugins/lock/conda_lock/conda_lock.py +++ b/conda-store-server/conda_store_server/_internal/plugins/lock/conda_lock/conda_lock.py @@ -17,9 +17,10 @@ class CondaLock(lock.LockPlugin): - def _conda_command(self, conda_store) -> str: - settings = conda_store.get_settings() - return settings.conda_command + def _conda_command(self, conda_store, namespace=None, environment=None) -> str: + return conda_store.get_setting( + "conda_command", namespace=namespace, environment_name=environment + ) def _conda_flags(self, conda_store) -> str: return conda_store.config.conda_flags @@ -32,7 +33,11 @@ def lock_environment( platforms: typing.List[str] = [conda_utils.conda_platform()], ) -> str: context.log.info("lock_environment entrypoint for conda-lock") - conda_command = self._conda_command(context.conda_store) + conda_command = self._conda_command( + context.conda_store, + namespace=context.namespace, + environment=context.environment, + ) conda_flags = self._conda_flags(context.conda_store) environment_filename = pathlib.Path.cwd() / "environment.yaml" diff --git a/conda-store-server/conda_store_server/_internal/worker/build.py b/conda-store-server/conda_store_server/_internal/worker/build.py index 04b25d3a8..fe9808718 100644 --- a/conda-store-server/conda_store_server/_internal/worker/build.py +++ b/conda-store-server/conda_store_server/_internal/worker/build.py @@ -239,6 +239,8 @@ def build_conda_environment(db: Session, conda_store, build): build=build, prefix=f"plugin-{lock_backend}: ", ), + namespace=build.environment.namespace.name, + environment=build.environment.name, ), ) diff --git a/conda-store-server/conda_store_server/plugins/plugin_context.py b/conda-store-server/conda_store_server/plugins/plugin_context.py index 4a80e443a..822844dec 100644 --- a/conda-store-server/conda_store_server/plugins/plugin_context.py +++ b/conda-store-server/conda_store_server/plugins/plugin_context.py @@ -9,19 +9,36 @@ class PluginContext: - """The plugin context provides some useful attributes to a hook. + """The plugin context provides some useful attributes and functions to a hook. This includes - * the variables: conda_store, log, stdout, stderr - * the functions: run_command, run + * the variables: conda_store, log, stdout, stderr, namespace, environment + * the functions: run_command + + Attributes + ---------- + conda_store : conda_store_server.conda_store + conda_store instance + log_level : int + logging level + stdout : io.StringIO + stream to write command output to + stderr : io.StringIO + stream to write command error output to + namespace : str + namespace context the plugin is running in + environment : str + environment context the plugin is running in """ def __init__( self, - conda_store=None, - stdout=None, - stderr=None, - log_level=logging.INFO, + conda_store, + stdout: io.StringIO | None = None, + stderr: io.StringIO | None = None, + log_level: int = logging.INFO, + namespace: str | None = None, + environment: str | None = None, ): if stdout is not None and stderr is None: stderr = stdout @@ -36,6 +53,8 @@ def __init__( self.log.addHandler(logging.StreamHandler(stream=self.stdout)) self.log.setLevel(log_level) self.conda_store = conda_store + self.namespace = namespace + self.environment = environment def run_command(self, command: str, redirect_stderr: bool = True, **kwargs): """Runs command and immediately writes to logs""" diff --git a/conda-store-server/tests/_internal/plugins/lock/test_conda_lock.py b/conda-store-server/tests/_internal/plugins/lock/test_conda_lock.py index f269acaa9..6e00e2d6f 100644 --- a/conda-store-server/tests/_internal/plugins/lock/test_conda_lock.py +++ b/conda-store-server/tests/_internal/plugins/lock/test_conda_lock.py @@ -13,6 +13,15 @@ from conda_store_server.plugins import plugin_context +def run_lock_side_effect(lockfile_path, **kwargs): + """Mock method to simulate the output of running a + lock with conda-lock. + Dumps dummy data to the expected lockfile output location. + """ + with open(lockfile_path, "w") as f: + yaml.dump({"foo": "bar"}, f) + + @pytest.mark.parametrize( "specification", [ @@ -29,12 +38,6 @@ def test_solve_lockfile( request, ): """Test that the call to conda_lock.run_lock is formed correctly.""" - - # Dump dummy data to the expected lockfile output location - def run_lock_side_effect(lockfile_path, **kwargs): - with open(lockfile_path, "w") as f: - yaml.dump({"foo": "bar"}, f) - mock_run_lock.side_effect = run_lock_side_effect platforms = [conda_utils.conda_platform()] @@ -74,6 +77,28 @@ def test_solve_lockfile_simple(conda_store, simple_specification): assert "zlib" in [pkg["name"] for pkg in lock_result["package"]] +@mock.patch("conda_store_server._internal.plugins.lock.conda_lock.conda_lock.run_lock") +def test_solve_right_conda_command(mock_run_lock, conda_store, simple_specification): + # Update conda_command settings + conda_store.set_settings(data={"conda_command": "conda"}) + + mock_run_lock.side_effect = run_lock_side_effect + + locker = conda_lock.CondaLock() + locker.lock_environment( + context=plugin_context.PluginContext( + conda_store, namespace="test", environment="one" + ), + spec=simple_specification, + platforms=[conda_utils.conda_platform()], + ) + + # Check that the call to `conda_lock` is correctly formed + mock_run_lock.assert_called_once() + call_args = mock_run_lock.call_args_list[0][1] + assert call_args["conda_exe"] == "conda" + + @pytest.mark.parametrize( "specification", [ diff --git a/conda-store-server/tests/plugins/test_plugin_context.py b/conda-store-server/tests/plugins/test_plugin_context.py index e3496221c..c4eec3d27 100644 --- a/conda-store-server/tests/plugins/test_plugin_context.py +++ b/conda-store-server/tests/plugins/test_plugin_context.py @@ -16,7 +16,9 @@ def test_run_command_no_logs(): out = io.StringIO() err = io.StringIO() - context = PluginContext(stdout=out, stderr=err, log_level=logging.ERROR) + context = PluginContext( + conda_store=None, stdout=out, stderr=err, log_level=logging.ERROR + ) context.run_command(["echo", "testing"]) assert err.getvalue() == "" @@ -26,7 +28,9 @@ def test_run_command_no_logs(): def test_run_command_log_info(): out = io.StringIO() err = io.StringIO() - context = PluginContext(stdout=out, stderr=err, log_level=logging.INFO) + context = PluginContext( + conda_store=None, stdout=out, stderr=err, log_level=logging.INFO + ) context.run_command(["echo", "testing"]) assert err.getvalue() == "" @@ -39,7 +43,7 @@ def test_run_command_log_info(): def test_run_command_errors(): - context = PluginContext(log_level=logging.ERROR) + context = PluginContext(conda_store=None, log_level=logging.ERROR) with pytest.raises(subprocess.CalledProcessError): context.run_command(["conda-store-server", "-thiswillreturnanonzeroexitcode"]) @@ -52,7 +56,9 @@ def test_run_command_kwargs(): """Ensure that kwargs get passed to subprocess""" out = io.StringIO() err = io.StringIO() - context = PluginContext(stdout=out, stderr=err, log_level=logging.ERROR) + context = PluginContext( + conda_store=None, stdout=out, stderr=err, log_level=logging.ERROR + ) # set the cwd to this directory and check that this file exists dir_path = os.path.dirname(os.path.realpath(__file__))