|
8 | 8 | from re import Pattern
|
9 | 9 | from typing import Any, List, Optional, Type
|
10 | 10 |
|
| 11 | +from pytest_plugins.logging import get_logger |
| 12 | + |
| 13 | +logger = get_logger(__name__) |
| 14 | + |
11 | 15 |
|
12 | 16 | class UnknownCLIError(Exception):
|
13 | 17 | """Exception raised if an unknown CLI is encountered."""
|
@@ -78,46 +82,90 @@ def from_binary_path(cls, *, binary_path: Optional[Path], **kwargs) -> Any:
|
78 | 82 | """
|
79 | 83 | assert cls.default_tool is not None, "default CLI implementation was never set"
|
80 | 84 |
|
| 85 | + # ensure provided t8n binary can be found and used |
81 | 86 | if binary_path is None:
|
| 87 | + logger.debug("Binary path of provided t8n is None!") |
82 | 88 | return cls.default_tool(binary=binary_path, **kwargs)
|
83 | 89 |
|
84 |
| - resolved_path = Path(os.path.expanduser(binary_path)).resolve() |
| 90 | + expanded_path = Path(os.path.expanduser(binary_path)) |
| 91 | + logger.debug(f"Expanded path of provided t8n: {expanded_path}") |
| 92 | + |
| 93 | + resolved_path = expanded_path.resolve() |
| 94 | + logger.debug(f"Resolved path of provided t8n: {resolved_path}") |
| 95 | + |
85 | 96 | if resolved_path.exists():
|
86 |
| - binary_path = resolved_path |
87 |
| - binary = shutil.which(binary_path) # type: ignore |
| 97 | + logger.debug("Resolved path exists") |
| 98 | + binary = Path(resolved_path) |
| 99 | + else: |
| 100 | + logger.debug( |
| 101 | + f"Resolved path does not exist: {resolved_path}\nTrying to find it via `which`" |
| 102 | + ) |
88 | 103 |
|
89 |
| - if not binary: |
90 |
| - raise CLINotFoundInPathError(binary=binary) |
| 104 | + # it might be that the provided binary exists in path |
| 105 | + filename = os.path.basename(resolved_path) |
| 106 | + binary = shutil.which(filename) # type: ignore |
| 107 | + logger.debug(f"Output of 'which {binary_path}': {binary}") |
91 | 108 |
|
92 |
| - binary = Path(binary) # type: ignore[assignment] |
| 109 | + if binary is None: |
| 110 | + logger.error(f"Resolved t8n binary path does not exist: {resolved_path}") |
| 111 | + raise CLINotFoundInPathError(binary=resolved_path) |
| 112 | + |
| 113 | + assert binary is not None |
| 114 | + logger.debug(f"Successfully located the path of the t8n binary: {binary}") |
| 115 | + binary = Path(binary) |
93 | 116 |
|
94 | 117 | # Group the tools by version flag, so we only have to call the tool once for all the
|
95 | 118 | # classes that share the same version flag
|
96 | 119 | for version_flag, subclasses in groupby(
|
97 | 120 | cls.registered_tools, key=lambda x: x.version_flag
|
98 | 121 | ):
|
| 122 | + logger.debug( |
| 123 | + f"Trying this `version` flag to determine if t8n supported: {version_flag}" |
| 124 | + ) |
| 125 | + # adding more logging reveals we check for `-v` twice.. |
| 126 | + |
99 | 127 | try:
|
100 | 128 | result = subprocess.run(
|
101 | 129 | [binary, version_flag], stdout=subprocess.PIPE, stderr=subprocess.PIPE
|
102 | 130 | )
|
| 131 | + logger.debug( |
| 132 | + f"Subprocess:\n\tstdout: {result.stdout}\n\n\n\tstderr: {result.stderr}\n\n\n" # type: ignore |
| 133 | + ) |
| 134 | + |
103 | 135 | if result.returncode != 0:
|
104 |
| - raise Exception(f"Non-zero return code: {result.returncode}") |
| 136 | + logger.debug(f"Subprocess returncode is not 0! It is: {result.returncode}") |
| 137 | + continue # don't raise exception, you are supposed to keep trying different version flags # noqa: E501 |
105 | 138 |
|
106 | 139 | if result.stderr:
|
107 |
| - raise Exception(f"Tool wrote to stderr: {result.stderr.decode()}") |
| 140 | + logger.debug(f"Stderr detected: {result.stderr}") # type: ignore |
| 141 | + continue |
108 | 142 |
|
109 | 143 | binary_output = ""
|
110 | 144 | if result.stdout:
|
111 | 145 | binary_output = result.stdout.decode().strip()
|
112 |
| - except Exception: |
113 |
| - # If the tool doesn't support the version flag, |
114 |
| - # we'll get an non-zero exit code. |
| 146 | + # e.g. 1.31.10+f62cfede9b4abfb5cd62d6f138240668620a2b0d should be treated as 1.31.10 # noqa: E501 |
| 147 | + # if "+" in binary_output: |
| 148 | + # binary_output = binary_output.split("+")[0] |
| 149 | + |
| 150 | + logger.debug(f"Stripped subprocess stdout: {binary_output}") |
| 151 | + |
| 152 | + for subclass in subclasses: |
| 153 | + logger.debug(f"Trying subclass {subclass}") |
| 154 | + |
| 155 | + if subclass.detect_binary(binary_output): |
| 156 | + return subclass(binary=binary, **kwargs) |
| 157 | + |
| 158 | + logger.debug( |
| 159 | + f"T8n with version {binary_output} does not belong to subclass {subclass}" |
| 160 | + ) |
| 161 | + |
| 162 | + except Exception as e: |
| 163 | + logger.debug( |
| 164 | + f"Trying to determine t8n version with flag `{version_flag}` failed: {e}" |
| 165 | + ) |
115 | 166 | continue
|
116 |
| - for subclass in subclasses: |
117 |
| - if subclass.detect_binary(binary_output): |
118 |
| - return subclass(binary=binary, **kwargs) |
119 | 167 |
|
120 |
| - raise UnknownCLIError(f"Unknown CLI: {binary_path}") |
| 168 | + raise UnknownCLIError(f"Unknown CLI: {binary}") |
121 | 169 |
|
122 | 170 | @classmethod
|
123 | 171 | def detect_binary(cls, binary_output: str) -> bool:
|
|
0 commit comments