def do_test(dirname):
        readonly = os.path.join(dirname, "readonly")
        print('CONDA_EXE: {}'.format(os.environ.get('CONDA_EXE')))
        # originally we did not specify a python version here, but we
        # needed to add it with python 3.8 was released because a compatible
        # version of ipython had not been created yet.
        conda_api.create(prefix=readonly, pkgs=['python<3.8'])

        assert os.path.isdir(readonly)
        assert os.path.isdir(os.path.join(readonly, "conda-meta"))
        assert os.path.exists(os.path.join(readonly, PYTHON_BINARY))

        readonly_mode = stat.S_IREAD | stat.S_IRGRP | stat.S_IROTH | stat.S_IEXEC | stat.S_IXGRP | stat.S_IXOTH
        os.chmod(readonly, readonly_mode)
        os.chmod(os.path.join(readonly, 'conda-meta'), readonly_mode)

        cloned = os.path.join(dirname, 'cloned')
        conda_api.clone(cloned, readonly)

        assert os.path.isdir(cloned)
        assert os.path.isdir(os.path.join(cloned, "conda-meta"))
        assert os.path.exists(os.path.join(cloned, PYTHON_BINARY))

        write_mode = (stat.S_IWUSR | stat.S_IWGRP
                      | stat.S_IWOTH) ^ readonly_mode
        os.chmod(readonly, write_mode)
        os.chmod(os.path.join(readonly, 'conda-meta'), write_mode)
    def do_test(dirname):
        missing = os.path.join(dirname, "missing")
        print('CONDA_EXE: {}'.format(os.environ.get('CONDA_EXE')))

        with pytest.raises(conda_api.CondaEnvMissingError) as excinfo:
            cloned = os.path.join(dirname, 'cloned')
            conda_api.clone(cloned, missing)
        assert 'missing' in repr(excinfo.value)
Ejemplo n.º 3
0
    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