Repository: conda/conda

Issue:
change name of 'condacmd' dir to 'condabin'; use on all platforms



Discussion:

Resolving patch:
diff --git a/conda/activate.py b/conda/activate.py
--- a/conda/activate.py
+++ b/conda/activate.py
@@ -97,6 +97,11 @@ def reactivate(self):
     def hook(self, auto_activate_base=None):
         builder = []
         builder.append(self._hook_preamble())
+
+        # here
+        condabin_dir = self.path_conversion(join(context.conda_prefix, "condabin"))
+        self.export_var_tmpl % ("PATH", self.pathsep_join((condabin_dir, )))
+
         with open(self.hook_source_path) as fsrc:
             builder.append(fsrc.read())
         if auto_activate_base is None and context.auto_activate_base or auto_activate_base:
@@ -422,6 +427,16 @@ def _add_prefix_to_path(self, prefix, starting_path_dirs=None):
             path_list = list(self.path_conversion(self._get_starting_path_list()))
         else:
             path_list = list(self.path_conversion(starting_path_dirs))
+
+        # If this is the first time we're activating an environment, we need to ensure that
+        # the condabin directory is included in the path list.
+        # Under normal conditions, if the shell hook is working correctly, this should
+        # never trigger.
+        old_conda_shlvl = int(self.environ.get('CONDA_SHLVL', '').strip() or 0)
+        if not old_conda_shlvl and not any(p.endswith("condabin") for p in path_list):
+            condabin_dir = self.path_conversion(join(context.conda_prefix, "condabin"))
+            path_list.insert(0, condabin_dir)
+
         path_list[0:0] = list(self.path_conversion(self._get_path_dirs2(prefix)))
         return tuple(path_list)
 
@@ -607,7 +622,7 @@ def _hook_preamble(self):
         if on_win:
             return ('export CONDA_EXE="$(cygpath \'%s\')"\n'
                     'export CONDA_BAT="%s"'
-                    % (context.conda_exe, join(context.conda_prefix, 'condacmd', 'conda.bat'))
+                    % (context.conda_exe, join(context.conda_prefix, 'condabin', 'conda.bat'))
                     )
         else:
             return 'export CONDA_EXE="%s"' % context.conda_exe
@@ -708,18 +723,6 @@ def _build_activate_shell_custom(self, export_vars):
     def _hook_preamble(self):
         raise NotImplementedError()
 
-    def _add_prefix_to_path(self, prefix, starting_path_dirs=None):
-        # If this is the first time we're activating an environment, we need to ensure that
-        # the condacmd directory is included in the path list.
-        old_conda_shlvl = int(self.environ.get('CONDA_SHLVL', '').strip() or 0)
-        if starting_path_dirs is None:
-            starting_path_dirs = self._get_starting_path_list()
-        starting_path_dirs = list(starting_path_dirs)
-        if not old_conda_shlvl and not any(p.endswith("condacmd") for p in starting_path_dirs):
-            condacmd_dir = self.path_conversion(join(context.conda_prefix, "condacmd"))
-            starting_path_dirs.insert(0, condacmd_dir)
-        return super(CmdExeActivator, self)._add_prefix_to_path(prefix, starting_path_dirs)
-
 
 class FishActivator(_Activator):
 
diff --git a/conda/cli/main_run.py b/conda/cli/main_run.py
--- a/conda/cli/main_run.py
+++ b/conda/cli/main_run.py
@@ -26,7 +26,7 @@ def _get_activated_env_vars_win(env_location):
     try:
         conda_bat = os.environ["CONDA_BAT"]
     except KeyError:
-        conda_bat = abspath(join(sys.prefix, 'condacmd', 'conda.bat'))
+        conda_bat = abspath(join(sys.prefix, 'condabin', 'conda.bat'))
 
     temp_path = None
     try:
diff --git a/conda/core/initialize.py b/conda/core/initialize.py
--- a/conda/core/initialize.py
+++ b/conda/core/initialize.py
@@ -198,9 +198,9 @@ def initialize_dev(shell, dev_env_prefix=None, conda_source_root=None):
         builder += ["@SET %s=" % unset_env_var for unset_env_var in unset_env_vars]
         builder += ['@SET "%s=%s"' % (key, env_vars[key]) for key in sorted(env_vars)]
         builder += [
-            '@CALL \"%s\"' % join(dev_env_prefix, 'condacmd', 'conda_hook.bat'),
+            '@CALL \"%s\"' % join(dev_env_prefix, 'condabin', 'conda_hook.bat'),
             '@IF %errorlevel% NEQ 0 @EXIT /B %errorlevel%',
-            '@CALL \"%s\" activate \"%s\"' % (join(dev_env_prefix, 'condacmd', 'conda.bat'),
+            '@CALL \"%s\" activate \"%s\"' % (join(dev_env_prefix, 'condabin', 'conda.bat'),
                                               dev_env_prefix),
             '@IF %errorlevel% NEQ 0 @EXIT /B %errorlevel%',
         ]
@@ -248,6 +248,16 @@ def make_install_plan(conda_prefix):
             },
         })
     else:
+        # We can't put a conda.exe in condabin on Windows. It'll conflict with conda.bat.
+        plan.append({
+            'function': make_entry_point.__name__,
+            'kwargs': {
+                'target_path': join(conda_prefix, 'condabin', 'conda'),
+                'conda_prefix': conda_prefix,
+                'module': 'conda.cli',
+                'func': 'main',
+            },
+        })
         conda_exe_path = join(conda_prefix, 'bin', 'conda')
         conda_env_exe_path = join(conda_prefix, 'bin', 'conda-env')
 
@@ -275,30 +285,30 @@ def make_install_plan(conda_prefix):
     # ######################################
     if on_win:
         plan.append({
-            'function': install_condacmd_conda_bat.__name__,
+            'function': install_condabin_conda_bat.__name__,
             'kwargs': {
-                'target_path': join(conda_prefix, 'condacmd', 'conda.bat'),
+                'target_path': join(conda_prefix, 'condabin', 'conda.bat'),
                 'conda_prefix': conda_prefix,
             },
         })
         plan.append({
-            'function': install_condacmd_conda_activate_bat.__name__,
+            'function': install_condabin_conda_activate_bat.__name__,
             'kwargs': {
-                'target_path': join(conda_prefix, 'condacmd', '_conda_activate.bat'),
+                'target_path': join(conda_prefix, 'condabin', '_conda_activate.bat'),
                 'conda_prefix': conda_prefix,
             },
         })
         plan.append({
-            'function': install_condacmd_conda_auto_activate_bat.__name__,
+            'function': install_condabin_conda_auto_activate_bat.__name__,
             'kwargs': {
-                'target_path': join(conda_prefix, 'condacmd', 'conda_auto_activate.bat'),
+                'target_path': join(conda_prefix, 'condabin', 'conda_auto_activate.bat'),
                 'conda_prefix': conda_prefix,
             },
         })
         plan.append({
-            'function': install_condacmd_hook_bat.__name__,
+            'function': install_condabin_hook_bat.__name__,
             'kwargs': {
-                'target_path': join(conda_prefix, 'condacmd', 'conda_hook.bat'),
+                'target_path': join(conda_prefix, 'condabin', 'conda_hook.bat'),
                 'conda_prefix': conda_prefix,
             },
         })
@@ -312,14 +322,14 @@ def make_install_plan(conda_prefix):
         plan.append({
             'function': install_activate_bat.__name__,
             'kwargs': {
-                'target_path': join(conda_prefix, 'condacmd', 'activate.bat'),
+                'target_path': join(conda_prefix, 'condabin', 'activate.bat'),
                 'conda_prefix': conda_prefix,
             },
         })
         plan.append({
             'function': install_deactivate_bat.__name__,
             'kwargs': {
-                'target_path': join(conda_prefix, 'condacmd', 'deactivate.bat'),
+                'target_path': join(conda_prefix, 'condabin', 'deactivate.bat'),
                 'conda_prefix': conda_prefix,
             },
         })
@@ -466,7 +476,7 @@ def make_initialize_plan(conda_prefix, shells, for_user, for_system, anaconda_pr
             plan.append({
                 'function': install_anaconda_prompt.__name__,
                 'kwargs': {
-                    'target_path': join(conda_prefix, 'condacmd', 'Anaconda Prompt.lnk'),
+                    'target_path': join(conda_prefix, 'condabin', 'Anaconda Prompt.lnk'),
                     'conda_prefix': conda_prefix,
                 },
             })
@@ -667,14 +677,14 @@ def make_entry_point_exe(target_path, conda_prefix):
 
 
 def install_anaconda_prompt(target_path, conda_prefix):
-    # target_path: join(conda_prefix, 'condacmd', 'Anaconda Prompt.lnk')
+    # target_path: join(conda_prefix, 'condabin', 'Anaconda Prompt.lnk')
     # target: join(os.environ["HOMEPATH"], "Desktop", "Anaconda Prompt.lnk")
     icon_path = join(CONDA_PACKAGE_ROOT, 'shell', 'conda_icon.ico')
 
     args = (
         '/K',
-        '""%s" && "%s""' % (join(conda_prefix, 'condacmd', 'conda_hook.bat'),
-                            join(conda_prefix, 'condacmd', 'conda_auto_activate.bat')),
+        '""%s" && "%s""' % (join(conda_prefix, 'condabin', 'conda_hook.bat'),
+                            join(conda_prefix, 'condabin', 'conda_auto_activate.bat')),
     )
     # The API for the call to 'create_shortcut' has 3
     # required arguments (path, description, filename)
@@ -730,16 +740,16 @@ def install_Scripts_activate_bat(target_path, conda_prefix):
 
 
 def install_activate_bat(target_path, conda_prefix):
-    # target_path: join(conda_prefix, 'condacmd', 'activate.bat')
-    src_path = join(CONDA_PACKAGE_ROOT, 'shell', 'condacmd', 'activate.bat')
+    # target_path: join(conda_prefix, 'condabin', 'activate.bat')
+    src_path = join(CONDA_PACKAGE_ROOT, 'shell', 'condabin', 'activate.bat')
     with open(src_path) as fsrc:
         file_content = fsrc.read()
     return _install_file(target_path, file_content)
 
 
 def install_deactivate_bat(target_path, conda_prefix):
-    # target_path: join(conda_prefix, 'condacmd', 'deactivate.bat')
-    src_path = join(CONDA_PACKAGE_ROOT, 'shell', 'condacmd', 'deactivate.bat')
+    # target_path: join(conda_prefix, 'condabin', 'deactivate.bat')
+    src_path = join(CONDA_PACKAGE_ROOT, 'shell', 'condabin', 'deactivate.bat')
     with open(src_path) as fsrc:
         file_content = fsrc.read()
     return _install_file(target_path, file_content)
@@ -769,33 +779,33 @@ def install_deactivate(target_path, conda_prefix):
     return _install_file(target_path, file_content)
 
 
-def install_condacmd_conda_bat(target_path, conda_prefix):
-    # target_path: join(conda_prefix, 'condacmd', 'conda.bat')
-    conda_bat_src_path = join(CONDA_PACKAGE_ROOT, 'shell', 'condacmd', 'conda.bat')
+def install_condabin_conda_bat(target_path, conda_prefix):
+    # target_path: join(conda_prefix, 'condabin', 'conda.bat')
+    conda_bat_src_path = join(CONDA_PACKAGE_ROOT, 'shell', 'condabin', 'conda.bat')
     with open(conda_bat_src_path) as fsrc:
         file_content = fsrc.read()
     return _install_file(target_path, file_content)
 
 
-def install_condacmd_conda_activate_bat(target_path, conda_prefix):
-    # target_path: join(conda_prefix, 'condacmd', '_conda_activate.bat')
-    conda_bat_src_path = join(CONDA_PACKAGE_ROOT, 'shell', 'condacmd', '_conda_activate.bat')
+def install_condabin_conda_activate_bat(target_path, conda_prefix):
+    # target_path: join(conda_prefix, 'condabin', '_conda_activate.bat')
+    conda_bat_src_path = join(CONDA_PACKAGE_ROOT, 'shell', 'condabin', '_conda_activate.bat')
     with open(conda_bat_src_path) as fsrc:
         file_content = fsrc.read()
     return _install_file(target_path, file_content)
 
 
-def install_condacmd_conda_auto_activate_bat(target_path, conda_prefix):
-    # target_path: join(conda_prefix, 'condacmd', 'conda_auto_activate.bat')
-    conda_bat_src_path = join(CONDA_PACKAGE_ROOT, 'shell', 'condacmd', 'conda_auto_activate.bat')
+def install_condabin_conda_auto_activate_bat(target_path, conda_prefix):
+    # target_path: join(conda_prefix, 'condabin', 'conda_auto_activate.bat')
+    conda_bat_src_path = join(CONDA_PACKAGE_ROOT, 'shell', 'condabin', 'conda_auto_activate.bat')
     with open(conda_bat_src_path) as fsrc:
         file_content = fsrc.read()
     return _install_file(target_path, file_content)
 
 
-def install_condacmd_hook_bat(target_path, conda_prefix):
-    # target_path: join(conda_prefix, 'condacmd', 'conda_hook.bat')
-    conda_bat_src_path = join(CONDA_PACKAGE_ROOT, 'shell', 'condacmd', 'conda_hook.bat')
+def install_condabin_hook_bat(target_path, conda_prefix):
+    # target_path: join(conda_prefix, 'condabin', 'conda_hook.bat')
+    conda_bat_src_path = join(CONDA_PACKAGE_ROOT, 'shell', 'condabin', 'conda_hook.bat')
     with open(conda_bat_src_path) as fsrc:
         file_content = fsrc.read()
     return _install_file(target_path, file_content)
@@ -1089,7 +1099,7 @@ def init_cmd_exe_registry(target_path, conda_prefix):
         prev_value = ""
         value_type = winreg.REG_EXPAND_SZ
 
-    hook_path = '"%s"' % join(conda_prefix, 'condacmd', 'conda_hook.bat')
+    hook_path = '"%s"' % join(conda_prefix, 'condabin', 'conda_hook.bat')
     replace_str = "__CONDA_REPLACE_ME_123__"
     new_value = re.sub(
         r'(\".*?conda[-_]hook\.bat\")',


Test patch:
diff --git a/tests/core/test_initialize.py b/tests/core/test_initialize.py
--- a/tests/core/test_initialize.py
+++ b/tests/core/test_initialize.py
@@ -21,7 +21,7 @@
 from conda.core.initialize import Result, _get_python_info, init_sh_system, init_sh_user, \
     initialize_dev, install, install_conda_csh, install_conda_fish, \
     install_conda_sh, install_conda_xsh, make_entry_point, make_entry_point_exe, \
-    make_initialize_plan, make_install_plan, install_condacmd_conda_bat
+    make_initialize_plan, make_install_plan, install_condabin_conda_bat
 from conda.exceptions import CondaValueError
 from conda.gateways.disk.create import create_link, mkdir_p
 from conda.models.enums import LinkType
@@ -102,31 +102,31 @@ def test_make_install_plan(self):
                         }
                     },
                     {
-                        "function": "install_condacmd_conda_bat",
+                        "function": "install_condabin_conda_bat",
                         "kwargs": {
                             "conda_prefix": "/darwin",
-                            "target_path": "/darwin\\condacmd\\conda.bat"
+                            "target_path": "/darwin\\condabin\\conda.bat"
                         }
                     },
                     {
-                        "function": "install_condacmd_conda_activate_bat",
+                        "function": "install_condabin_conda_activate_bat",
                         "kwargs": {
                             "conda_prefix": "/darwin",
-                            "target_path": "/darwin\\condacmd\\_conda_activate.bat"
+                            "target_path": "/darwin\\condabin\\_conda_activate.bat"
                         }
                     },
                     {
-                        "function": "install_condacmd_conda_auto_activate_bat",
+                        "function": "install_condabin_conda_auto_activate_bat",
                         "kwargs": {
                             "conda_prefix": "/darwin",
-                            "target_path": "/darwin\\condacmd\\conda_auto_activate.bat"
+                            "target_path": "/darwin\\condabin\\conda_auto_activate.bat"
                         }
                     },
                     {
-                        "function": "install_condacmd_hook_bat",
+                        "function": "install_condabin_hook_bat",
                         "kwargs": {
                             "conda_prefix": "/darwin",
-                            "target_path": "/darwin\\condacmd\\conda_hook.bat"
+                            "target_path": "/darwin\\condabin\\conda_hook.bat"
                         }
                     },
                     {
@@ -140,14 +140,14 @@ def test_make_install_plan(self):
                         "function": "install_activate_bat",
                         "kwargs": {
                             "conda_prefix": "/darwin",
-                            "target_path": "/darwin\\condacmd\\activate.bat"
+                            "target_path": "/darwin\\condabin\\activate.bat"
                         }
                     },
                     {
                         "function": "install_deactivate_bat",
                         "kwargs": {
                             "conda_prefix": "/darwin",
-                            "target_path": "/darwin\\condacmd\\deactivate.bat"
+                            "target_path": "/darwin\\condabin\\deactivate.bat"
                         }
                     },
                     {
@@ -195,6 +195,15 @@ def test_make_install_plan(self):
                 ]
             else:
                 assert plan == [
+                    {
+                        "function": "make_entry_point",
+                        "kwargs": {
+                            "conda_prefix": "/darwin",
+                            "func": "main",
+                            "module": "conda.cli",
+                            "target_path": "/darwin/condabin/conda"
+                        }
+                    },
                     {
                         "function": "make_entry_point",
                         "kwargs": {
@@ -337,7 +346,7 @@ def test_install_conda_sh(self):
             if on_win:
                 first_line, second_line, remainder = created_file_contents.split('\n', 2)
                 assert first_line == "export CONDA_EXE=\"$(cygpath '%s')\"" % context.conda_exe
-                assert second_line == "export CONDA_BAT=\"%s\"" % join(context.conda_prefix, 'condacmd', 'conda.bat')
+                assert second_line == "export CONDA_BAT=\"%s\"" % join(context.conda_prefix, 'condabin', 'conda.bat')
             else:
                 first_line, remainder = created_file_contents.split('\n', 1)
                 assert first_line == 'export CONDA_EXE="%s"' % context.conda_exe
@@ -427,11 +436,11 @@ def test_install_conda_csh(self):
             result = install_conda_csh(target_path, conda_prefix)
             assert result == Result.NO_CHANGE
 
-    def test_install_condacmd_conda_bat(self):
+    def test_install_condabin_conda_bat(self):
         with tempdir() as conda_temp_prefix:
             conda_prefix = abspath(sys.prefix)
-            target_path = join(conda_temp_prefix, 'condacmd', 'conda.bat')
-            result = install_condacmd_conda_bat(target_path, conda_prefix)
+            target_path = join(conda_temp_prefix, 'condabin', 'conda.bat')
+            result = install_condabin_conda_bat(target_path, conda_prefix)
             assert result == Result.MODIFIED
 
             with open(target_path) as fh:
@@ -439,11 +448,11 @@ def test_install_condacmd_conda_bat(self):
 
             remainder = created_file_contents
 
-            with open(join(CONDA_PACKAGE_ROOT, 'shell', 'condacmd', 'conda.bat')) as fh:
+            with open(join(CONDA_PACKAGE_ROOT, 'shell', 'condabin', 'conda.bat')) as fh:
                 original_contents = fh.read()
             assert remainder == original_contents
 
-            result = install_condacmd_conda_bat(target_path, conda_prefix)
+            result = install_condabin_conda_bat(target_path, conda_prefix)
             assert result == Result.NO_CHANGE
 
     def test__get_python_info(self):
@@ -480,7 +489,8 @@ def test_install_1(self):
             )
         else:
             modified_files = (
-                'conda',
+                'conda',  # condabin/conda
+                'conda',  # bin/conda
                 'conda-env',
                 'activate',
                 'deactivate',
@@ -538,7 +548,8 @@ def test_initialize_dev_bash(self):
             )
         else:
             modified_files = (
-                'conda',
+                'conda',  # condabin/conda
+                'conda',  # bin/conda
                 'conda-env',
                 'activate',
                 'deactivate',
@@ -600,7 +611,8 @@ def test_initialize_dev_cmd_exe(self):
             )
         else:
             modified_files = (
-                'conda',
+                'conda',  # condabin/conda
+                'conda',  # bin/conda
                 'conda-env',
                 'activate',
                 'deactivate',
@@ -769,7 +781,7 @@ def _read_windows_registry_mock(target_path):
             initialize._read_windows_registry = orig_read_windows_registry
             initialize.join = orig_join
 
-        expected = "echo hello & \"c:\\Users\\Lars\\miniconda\\condacmd\\conda_hook.bat\" & echo \"world\""
+        expected = "echo hello & \"c:\\Users\\Lars\\miniconda\\condabin\\conda_hook.bat\" & echo \"world\""
         assert c.stdout.strip().splitlines()[-1][1:] == expected
 
     @pytest.mark.skipif(not on_win, reason="win-only test")
diff --git a/tests/test_activate.py b/tests/test_activate.py
--- a/tests/test_activate.py
+++ b/tests/test_activate.py
@@ -113,7 +113,8 @@ def test_add_prefix_to_path_posix(self):
             added_paths = added_paths,
 
         new_path = activator._add_prefix_to_path(test_prefix, path_dirs)
-        assert new_path == added_paths + path_dirs
+        condabin_dir = context.conda_prefix + "/condabin"
+        assert new_path == added_paths + (condabin_dir,) + path_dirs
 
     @pytest.mark.skipif(not on_win, reason="windows-specific test")
     def test_add_prefix_to_path_cmdexe(self):
@@ -130,7 +131,7 @@ def test_add_prefix_to_path_cmdexe(self):
         assert new_path[:len(added_paths)] == added_paths
         assert new_path[-len(path_dirs):] == path_dirs
         assert len(new_path) == len(added_paths) + len(path_dirs) + 1
-        assert new_path[len(added_paths)].endswith("condacmd")
+        assert new_path[len(added_paths)].endswith("condabin")
 
     def test_remove_prefix_from_path_1(self):
         activator = PosixActivator()
@@ -1144,7 +1145,7 @@ class InteractiveShell(object):
         'cmd.exe': {
             'activator': 'cmd.exe',
             'init_command': 'set "CONDA_SHLVL=" '
-                            '&& @CALL conda\\shell\\condacmd\\conda_hook.bat '
+                            '&& @CALL conda\\shell\\condabin\\conda_hook.bat '
                             '&& set "CONDA_EXE=python -m conda"',
             'print_env_var': '@echo %%%s%%',
         },
@@ -1286,6 +1287,7 @@ def basic_posix(self, shell):
         num_paths_added = len(tuple(PosixActivator()._get_path_dirs(self.prefix)))
         shell.assert_env_var('CONDA_SHLVL', '0')
         PATH0 = shell.get_env_var('PATH').strip(':')
+        assert any(p.endswith("condabin") for p in PATH0.split(":"))
 
         shell.sendline('conda activate base')
         # shell.sendline('env | sort')
diff --git a/tests/test_create.py b/tests/test_create.py
--- a/tests/test_create.py
+++ b/tests/test_create.py
@@ -925,7 +925,7 @@ def test_install_freeze_installed_flag(self):
                 run_command(Commands.INSTALL, prefix,
                             "conda-forge::tensorflow>=1.4 --dry-run --freeze-installed")
 
-    @pytest.mark.xfail(on_win and datetime.now() < datetime(2018, 9, 15),
+    @pytest.mark.xfail(on_win and datetime.now() < datetime(2018, 10, 1),
                        reason="need to talk with @msarahan about blas patches on Windows",
                        strict=True)
     def test_install_features(self):
diff --git a/tests/test_resolve.py b/tests/test_resolve.py
--- a/tests/test_resolve.py
+++ b/tests/test_resolve.py
@@ -1025,7 +1025,7 @@ def test_no_features():
     ]
 
 
-@pytest.mark.skipif(datetime.now() < datetime(2018, 9, 15), reason="bogus test; talk with @mcg1969")
+@pytest.mark.skipif(datetime.now() < datetime(2018, 10, 1), reason="bogus test; talk with @mcg1969")
 def test_multiple_solution():
     assert False
 #    index2 = index.copy()