Make _WinBashStatus instances carry all their info · gitpython-developers/GitPython@7ff3cee

@@ -3,7 +3,6 @@

33

# This module is part of GitPython and is released under the

44

# 3-Clause BSD License: https://opensource.org/license/bsd-3-clause/

556-

import enum

76

from io import BytesIO

87

import logging

98

import os

@@ -14,6 +13,7 @@

1413

import tempfile

15141615

import pytest

16+

from sumtypes import constructor, sumtype

17171818

from git import (

1919

IndexFile,

@@ -39,35 +39,34 @@

3939

log = logging.getLogger(__name__)

4040414142-

@enum.unique

43-

class _WinBashStatus(enum.Enum):

42+

@sumtype

43+

class _WinBashStatus:

4444

"""Status of bash.exe for native Windows. Affects which commit hook tests can pass.

45454646

Call :meth:`check` to check the status.

4747

"""

484849-

INAPPLICABLE = enum.auto()

49+

Inapplicable = constructor()

5050

"""This system is not native Windows: either not Windows at all, or Cygwin."""

515152-

ABSENT = enum.auto()

52+

Absent = constructor()

5353

"""No command for ``bash.exe`` is found on the system."""

545455-

NATIVE = enum.auto()

55+

Native = constructor()

5656

"""Running ``bash.exe`` operates outside any WSL distribution (as with Git Bash)."""

575758-

WSL = enum.auto()

58+

Wsl = constructor()

5959

"""Running ``bash.exe`` calls ``bash`` in a WSL distribution."""

606061-

WSL_NO_DISTRO = enum.auto()

61+

WslNoDistro = constructor()

6262

"""Running ``bash.exe` tries to run bash on a WSL distribution, but none exists."""

636364-

ERROR_WHILE_CHECKING = enum.auto()

64+

ErrorWhileChecking = constructor("error_or_process")

6565

"""Could not determine the status.

66666767

This should not trigger a skip or xfail, as it typically indicates either a fixable

6868

problem on the test machine, such as an "Insufficient system resources exist to

6969

complete the requested service" error starting WSL, or a bug in this detection code.

70-

``ERROR_WHILE_CHECKING.error_or_process`` has details about the most recent failure.

7170

"""

72717372

@classmethod

@@ -93,7 +92,13 @@ def check(cls):

9392

administrators occasionally put executables there in lieu of extending ``PATH``.

9493

"""

9594

if os.name != "nt":

96-

return cls.INAPPLICABLE

95+

return cls.Inapplicable()

96+97+

no_distro_message = "Windows Subsystem for Linux has no installed distributions."

98+99+

def error_running_bash(error):

100+

log.error("Error running bash.exe to check WSL status: %s", error)

101+

return cls.ErrorWhileChecking(error)

9710298103

try:

99104

# Output rather than forwarding the test command's exit status so that if a

@@ -103,30 +108,21 @@ def check(cls):

103108

command = ["bash.exe", "-c", script]

104109

proc = subprocess.run(command, capture_output=True, check=True, text=True)

105110

except FileNotFoundError:

106-

return cls.ABSENT

111+

return cls.Absent()

107112

except OSError as error:

108-

return cls._error(error)

113+

return error_running_bash(error)

109114

except subprocess.CalledProcessError as error:

110-

no_distro_message = "Windows Subsystem for Linux has no installed distributions."

111115

if error.returncode == 1 and error.stdout.startswith(no_distro_message):

112-

return cls.WSL_NO_DISTRO

113-

return cls._error(error)

116+

return cls.WslNoDistro()

117+

return error_running_bash(error)

114118115119

status = proc.stdout.rstrip()

116120

if status == "0":

117-

return cls.WSL

121+

return cls.Wsl()

118122

if status == "1":

119-

return cls.NATIVE

120-

return cls._error(proc)

121-122-

@classmethod

123-

def _error(cls, error_or_process):

124-

if isinstance(error_or_process, subprocess.CompletedProcess):

125-

log.error("Strange output checking WSL status: %s", error_or_process.stdout)

126-

else:

127-

log.error("Error running bash.exe to check WSL status: %s", error_or_process)

128-

cls.ERROR_WHILE_CHECKING.error_or_process = error_or_process

129-

return cls.ERROR_WHILE_CHECKING

123+

return cls.Native()

124+

log.error("Strange output checking WSL status: %s", proc.stdout)

125+

return cls.ErrorWhileChecking(proc)

130126131127132128

_win_bash_status = _WinBashStatus.check()

@@ -1001,7 +997,7 @@ class Mocked:

1001997

self.assertEqual(rel, os.path.relpath(path, root))

10029981003999

@pytest.mark.xfail(

1004-

_win_bash_status is _WinBashStatus.WSL_NO_DISTRO,

1000+

type(_win_bash_status) is _WinBashStatus.WslNoDistro,

10051001

reason="Currently uses the bash.exe for WSL even with no WSL distro installed",

10061002

raises=HookExecutionError,

10071003

)

@@ -1012,7 +1008,7 @@ def test_pre_commit_hook_success(self, rw_repo):

10121008

index.commit("This should not fail")

1013100910141010

@pytest.mark.xfail(

1015-

_win_bash_status is _WinBashStatus.WSL_NO_DISTRO,

1011+

type(_win_bash_status) is _WinBashStatus.WslNoDistro,

10161012

reason="Currently uses the bash.exe for WSL even with no WSL distro installed",

10171013

raises=AssertionError,

10181014

)

@@ -1023,7 +1019,7 @@ def test_pre_commit_hook_fail(self, rw_repo):

10231019

try:

10241020

index.commit("This should fail")

10251021

except HookExecutionError as err:

1026-

if _win_bash_status is _WinBashStatus.ABSENT:

1022+

if type(_win_bash_status) is _WinBashStatus.Absent:

10271023

self.assertIsInstance(err.status, OSError)

10281024

self.assertEqual(err.command, [hp])

10291025

self.assertEqual(err.stdout, "")

@@ -1039,12 +1035,12 @@ def test_pre_commit_hook_fail(self, rw_repo):

10391035

raise AssertionError("Should have caught a HookExecutionError")

1040103610411037

@pytest.mark.xfail(

1042-

_win_bash_status in {_WinBashStatus.ABSENT, _WinBashStatus.WSL},

1038+

type(_win_bash_status) in {_WinBashStatus.Absent, _WinBashStatus.Wsl},

10431039

reason="Specifically seems to fail on WSL bash (in spite of #1399)",

10441040

raises=AssertionError,

10451041

)

10461042

@pytest.mark.xfail(

1047-

_win_bash_status is _WinBashStatus.WSL_NO_DISTRO,

1043+

type(_win_bash_status) is _WinBashStatus.WslNoDistro,

10481044

reason="Currently uses the bash.exe for WSL even with no WSL distro installed",

10491045

raises=HookExecutionError,

10501046

)

@@ -1062,7 +1058,7 @@ def test_commit_msg_hook_success(self, rw_repo):

10621058

self.assertEqual(new_commit.message, "{} {}".format(commit_message, from_hook_message))

1063105910641060

@pytest.mark.xfail(

1065-

_win_bash_status is _WinBashStatus.WSL_NO_DISTRO,

1061+

type(_win_bash_status) is _WinBashStatus.WslNoDistro,

10661062

reason="Currently uses the bash.exe for WSL even with no WSL distro installed",

10671063

raises=AssertionError,

10681064

)

@@ -1073,7 +1069,7 @@ def test_commit_msg_hook_fail(self, rw_repo):

10731069

try:

10741070

index.commit("This should fail")

10751071

except HookExecutionError as err:

1076-

if _win_bash_status is _WinBashStatus.ABSENT:

1072+

if type(_win_bash_status) is _WinBashStatus.Absent:

10771073

self.assertIsInstance(err.status, OSError)

10781074

self.assertEqual(err.command, [hp])

10791075

self.assertEqual(err.stdout, "")