def provide(self, requirement, context): """Override superclass to create or update our environment.""" assert 'PATH' in context.environ conda = new_conda_manager(context.frontend) # set from the inherited vale if necessary if context.status.analysis.config['source'] == 'inherited': context.environ[ requirement.env_var] = context.status.analysis.config['value'] # set the env var (but not PATH, etc. to fully activate, that's done below) super_result = super(CondaBootstrapEnvProvider, self).provide(requirement, context) project_dir = context.environ['PROJECT_DIR'] env_name = context.status.analysis.config.get( 'env_name', context.default_env_spec_name) env_spec = requirement.env_specs.get(env_name) prefix = os.path.join(project_dir, 'envs', 'bootstrap-env') # if the value has changed, choose the matching env spec # (something feels wrong here; should this be in read_config? # or not at all?) for env in requirement.env_specs.values(): if env.path(project_dir) == prefix: env_spec = env break if context.mode != PROVIDE_MODE_CHECK: # we update the environment in both prod and dev mode # TODO if not creating a named env, we could use the # shared packages, but for now we leave it alone assert env_spec is not None try: conda.fix_environment_deviations(prefix, env_spec, create=True) except CondaManagerError as e: return super_result.copy_with_additions(errors=[str(e)]) conda_api.environ_set_prefix(context.environ, prefix, varname=requirement.env_var) path = context.environ.get("PATH", "") context.environ["PATH"] = conda_api.set_conda_env_in_path(path, prefix) # Some stuff can only be done when a shell is launched: # - we can't set PS1 because it shouldn't be exported. # - we can't run conda activate scripts because they are sourced. # We can do these in the output of our activate command, but not here. return super_result
def prepare_project_scoped_env(dirname): project = Project(dirname) fake_old_path = "foo" + os.pathsep + "bar" environ = dict(PROJECT_DIR=dirname, PATH=fake_old_path) result = prepare_without_interaction(project, environ=environ) assert result expected_env = os.path.join(dirname, "envs", "bootstrap-env") if platform.system() == 'Windows': expected_new_path = expected_env + os.pathsep + os.path.join( expected_env, script_dir) + os.pathsep + os.path.join( expected_env, "Library", "bin") + os.pathsep + "foo" + os.pathsep + "bar" else: expected_new_path = os.path.join( expected_env, script_dir) + os.pathsep + "foo" + os.pathsep + "bar" expected = dict(PROJECT_DIR=project.directory_path, PATH=expected_new_path, BOOTSTRAP_ENV_PREFIX=expected_env) conda_api.environ_set_prefix(expected, expected_env) expected == result.environ assert os.path.exists(os.path.join(expected_env, "conda-meta")) conda_meta_mtime = os.path.getmtime( os.path.join(expected_env, "conda-meta")) # bare minimum bootstrap-env env shouldn't include these # (contrast with the test later where we list them in # requirements) installed = conda_api.installed(expected_env) assert 'ipython' not in installed assert 'numpy' not in installed # Prepare it again should no-op (use the already-existing environment) environ = dict(PROJECT_DIR=dirname, PATH=fake_old_path) result = prepare_without_interaction(project, environ=environ) assert result expected = dict(PROJECT_DIR=project.directory_path, PATH=expected_new_path) conda_api.environ_set_prefix(expected, expected_env) assert conda_meta_mtime == os.path.getmtime( os.path.join(expected_env, "conda-meta")) # Now unprepare status = unprepare(project, result) assert status # todo: this differs from standard CondaEnvProvider assert status.status_description == 'Success.' assert status.errors == [] assert not os.path.exists(expected_env)
def test_environ_set_prefix_to_root(): prefix = conda_api.resolve_env_to_prefix('root') environ = dict() conda_api.environ_set_prefix(environ, prefix, varname='CONDA_PREFIX') assert environ['CONDA_PREFIX'] == prefix assert environ['CONDA_DEFAULT_ENV'] == 'root'
def provide(self, requirement, context): """Override superclass to create or update our environment.""" assert 'PATH' in context.environ conda = new_conda_manager(context.frontend) # set from the inherited vale if necessary if context.status.analysis.config['source'] == 'inherited': context.environ[ requirement.env_var] = context.status.analysis.config['value'] # set the env var (but not PATH, etc. to fully activate, that's done below) super_result = super(CondaEnvProvider, self).provide(requirement, context) project_dir = context.environ['PROJECT_DIR'] env_name = context.status.analysis.config.get( 'env_name', context.default_env_spec_name) env_spec = requirement.env_specs.get(env_name) if env_name == 'bootstrap-env': # The bootstrap environment is always stored in the project directory # TODO: have this respect ANACONDA_PROJECT_ENVS_PATH prefix = os.path.join(project_dir, 'envs', 'bootstrap-env') elif context.status.analysis.config['source'] == 'inherited': prefix = context.environ.get(requirement.env_var, None) inherited = True else: prefix = None inherited = False if prefix is None: # use the default environment prefix = env_spec.path(project_dir) assert prefix is not None # if the value has changed, choose the matching env spec # (something feels wrong here; should this be in read_config? # or not at all?) for env in requirement.env_specs.values(): if env.path(project_dir) == prefix: env_spec = env break if context.mode != PROVIDE_MODE_CHECK: # we update the environment in both prod and dev mode # TODO if not creating a named env, we could use the # shared packages, but for now we leave it alone assert env_spec is not None deviations = conda.find_environment_deviations(prefix, env_spec) readonly_policy = os.environ.get( 'ANACONDA_PROJECT_READONLY_ENVS_POLICY', 'fail').lower() if deviations.unfixable and readonly_policy in ('clone', 'replace'): # scan for writable path destination = env_spec.path(project_dir, reset=True, force_writable=True) if destination != prefix: if readonly_policy == 'replace': print('Replacing the readonly environment {}'.format( prefix)) deviations = conda.find_environment_deviations( destination, env_spec) else: print('Cloning the readonly environment {}'.format( prefix)) conda_api.clone( destination, prefix, stdout_callback=context.frontend.partial_info, stderr_callback=context.frontend.partial_error) prefix = destination try: conda.fix_environment_deviations(prefix, env_spec, create=(not inherited)) except CondaManagerError as e: return super_result.copy_with_additions(errors=[str(e)]) conda_api.environ_set_prefix(context.environ, prefix, varname=requirement.env_var) path = context.environ.get("PATH", "") context.environ["PATH"] = conda_api.set_conda_env_in_path(path, prefix) # Some stuff can only be done when a shell is launched: # - we can't set PS1 because it shouldn't be exported. # - we can't run conda activate scripts because they are sourced. # We can do these in the output of our activate command, but not here. return super_result