Repository: pypa/virtualenv

Issue:
20b1 feedback: Unable to generate bash "activate" script on Windows.
Hello!

Working on Windows 10, using Git Bash as my default shell pretty much everywhere.

From my understanding, the bash activation script is not generated by default on Windows anymore.
That's going to break users in a similar solution to mine.

But the really bad news for me:
```
$ python -m virtualenv --activators bash myvirtualenv
usage: virtualenv [--version] [-v | -q] [--discovery {builtin}] [-p py] [--creator {builtin,cpython2-win}] [--seeder {app-data,none,pip}] [--without-pip] [--activators comma_separated_list]
virtualenv: error: argument --activators: the following activators are not available bash
```
`bash` is considered not available on Windows, and that's a no-go for me, or anyone using a bash equivalent on Windows.

I'd plead for keeping bash script by default on Windows.
Or at the very least, allow it as an option, although its still going to be a pain.

Cheers!



Discussion:

Patch:
diff --git a/docs/changelog/1527.bugfix.rst b/docs/changelog/1527.bugfix.rst
new file mode 100644
index 00000000..ac3d680c
--- /dev/null
+++ b/docs/changelog/1527.bugfix.rst
@@ -0,0 +1,2 @@
+Generate ``bash`` and ``fish`` activators on Windows too (as these can be available with git bash, cygwin or mysys2)
+- by ``gaborbernat``.
diff --git a/src/virtualenv/activation/bash/__init__.py b/src/virtualenv/activation/bash/__init__.py
index df3f7727..22c90c38 100644
--- a/src/virtualenv/activation/bash/__init__.py
+++ b/src/virtualenv/activation/bash/__init__.py
@@ -6,10 +6,6 @@ from ..via_template import ViaTemplateActivator
 
 
 class BashActivator(ViaTemplateActivator):
-    @classmethod
-    def supports(cls, interpreter):
-        return interpreter.os != "nt"
-
     def templates(self):
         yield Path("activate.sh")
 
diff --git a/src/virtualenv/activation/fish/__init__.py b/src/virtualenv/activation/fish/__init__.py
index 3671093a..8d0e19c2 100644
--- a/src/virtualenv/activation/fish/__init__.py
+++ b/src/virtualenv/activation/fish/__init__.py
@@ -8,7 +8,3 @@ from ..via_template import ViaTemplateActivator
 class FishActivator(ViaTemplateActivator):
     def templates(self):
         yield Path("activate.fish")
-
-    @classmethod
-    def supports(cls, interpreter):
-        return interpreter.os != "nt"
diff --git a/src/virtualenv/util/subprocess/_win_subprocess.py b/src/virtualenv/util/subprocess/_win_subprocess.py
index f30344dd..67503030 100644
--- a/src/virtualenv/util/subprocess/_win_subprocess.py
+++ b/src/virtualenv/util/subprocess/_win_subprocess.py
@@ -4,6 +4,7 @@
 
 import ctypes
 import os
+import platform
 import subprocess
 from ctypes import Structure, WinError, byref, c_char_p, c_void_p, c_wchar, c_wchar_p, sizeof, windll
 from ctypes.wintypes import BOOL, BYTE, DWORD, HANDLE, LPVOID, LPWSTR, WORD
@@ -133,7 +134,10 @@ class Popen(subprocess.Popen):
         if startupinfo is None:
             startupinfo = subprocess.STARTUPINFO()
         if not isinstance(args, subprocess.types.StringTypes):
+            args = [i if isinstance(i, bytes) else i.encode('utf-8') for i in args]
             args = subprocess.list2cmdline(args)
+            if platform.python_implementation() == "CPython":
+                args = args.decode('utf-8')
         startupinfo.dwFlags |= _subprocess.STARTF_USESHOWWINDOW
         startupinfo.wShowWindow = _subprocess.SW_HIDE
         comspec = os.environ.get("COMSPEC", unicode("cmd.exe"))


Test patch:
diff --git a/tests/unit/activation/test_activation_support.py b/tests/unit/activation/test_activation_support.py
index fd054c62..6168856d 100644
--- a/tests/unit/activation/test_activation_support.py
+++ b/tests/unit/activation/test_activation_support.py
@@ -15,7 +15,9 @@ from virtualenv.activation import (
 from virtualenv.discovery.py_info import PythonInfo
 
 
-@pytest.mark.parametrize("activator_class", [BatchActivator, PowerShellActivator, PythonActivator])
+@pytest.mark.parametrize(
+    "activator_class", [BatchActivator, PowerShellActivator, PythonActivator, BashActivator, FishActivator]
+)
 def test_activator_support_windows(mocker, activator_class):
     activator = activator_class(Namespace(prompt=None))
 
@@ -24,7 +26,7 @@ def test_activator_support_windows(mocker, activator_class):
     assert activator.supports(interpreter)
 
 
-@pytest.mark.parametrize("activator_class", [BashActivator, CShellActivator, FishActivator])
+@pytest.mark.parametrize("activator_class", [CShellActivator])
 def test_activator_no_support_windows(mocker, activator_class):
     activator = activator_class(Namespace(prompt=None))
 
diff --git a/tests/unit/activation/test_fish.py b/tests/unit/activation/test_fish.py
index 4b853389..4e55415d 100644
--- a/tests/unit/activation/test_fish.py
+++ b/tests/unit/activation/test_fish.py
@@ -1,8 +1,12 @@
 from __future__ import absolute_import, unicode_literals
 
+import pytest
+
 from virtualenv.activation import FishActivator
+from virtualenv.info import IS_WIN
 
 
+@pytest.mark.skipif(IS_WIN, reason="we have not setup fish in CI yet")
 def test_fish(activation_tester_class, activation_tester):
     class Fish(activation_tester_class):
         def __init__(self, session):
diff --git a/tests/unit/discovery/test_discovery.py b/tests/unit/discovery/test_discovery.py
index 770c1cc2..e4fe556c 100644
--- a/tests/unit/discovery/test_discovery.py
+++ b/tests/unit/discovery/test_discovery.py
@@ -36,6 +36,6 @@ def test_discovery_via_path(monkeypatch, case, special_name_dir, caplog):
 
 
 def test_discovery_via_path_not_found(tmp_path, monkeypatch):
-    monkeypatch.setenv("PATH", str(tmp_path))
+    monkeypatch.setenv(str("PATH"), str(tmp_path))
     interpreter = get_interpreter(uuid4().hex)
     assert interpreter is None