add uncommitted files
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
from .models import ProjectKind, Toolchain
|
||||
|
||||
VC_WORKLOAD = "Microsoft.VisualStudio.Component.VC.Tools.x86.x64"
|
||||
VS_CMAKE_RELATIVE = Path(
|
||||
"Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/bin"
|
||||
)
|
||||
|
||||
|
||||
class ToolchainError(RuntimeError):
|
||||
pass
|
||||
|
||||
|
||||
def _decode(value):
|
||||
if isinstance(value, str):
|
||||
return value
|
||||
return (value or b"").decode("utf-8", errors="replace")
|
||||
|
||||
|
||||
def _first_path(result, label, argv, cwd):
|
||||
text = _decode(result.stdout).strip()
|
||||
if result.returncode != 0:
|
||||
diagnostic = (
|
||||
_decode(result.stdout) + "\n" + _decode(result.stderr)
|
||||
).rstrip()[-8000:]
|
||||
diagnostic = diagnostic.replace("\r\n", " | ").replace("\n", " | ")
|
||||
message = (
|
||||
f"{label} probe failed with exit code {result.returncode}; "
|
||||
f"argv={argv!r}; cwd={str(cwd)!r}"
|
||||
)
|
||||
if diagnostic:
|
||||
message = f"{message}; output tail: {diagnostic}"
|
||||
raise ToolchainError(
|
||||
f"{message}; install Visual Studio Desktop development with C++"
|
||||
)
|
||||
if not text:
|
||||
raise ToolchainError(
|
||||
f"{label} probe returned no path; argv={argv!r}; cwd={str(cwd)!r}; "
|
||||
"install Visual Studio Desktop development with C++"
|
||||
)
|
||||
path = Path(text.splitlines()[0]).resolve()
|
||||
if not path.exists():
|
||||
diagnostic = (
|
||||
_decode(result.stdout) + "\n" + _decode(result.stderr)
|
||||
).rstrip()[-8000:]
|
||||
diagnostic = diagnostic.replace("\r\n", " | ").replace("\n", " | ")
|
||||
message = (
|
||||
f"{label} probe returned nonexistent path with exit code 0; "
|
||||
f"argv={argv!r}; cwd={str(cwd)!r}"
|
||||
)
|
||||
if diagnostic:
|
||||
message = f"{message}; output tail: {diagnostic}"
|
||||
raise ToolchainError(
|
||||
f"{message}; install or repair Visual Studio Desktop development with C++"
|
||||
)
|
||||
return path
|
||||
|
||||
|
||||
def _require_path(path, label):
|
||||
if path is None or not path.exists():
|
||||
raise ToolchainError(f"{label} not found")
|
||||
return path.resolve()
|
||||
|
||||
|
||||
def _remaining(deadline, clock, label):
|
||||
if deadline is None:
|
||||
return None
|
||||
remaining = deadline - clock()
|
||||
if remaining <= 0:
|
||||
raise ToolchainError(f"{label} probe timed out before it could start")
|
||||
return remaining
|
||||
|
||||
|
||||
def _probe(run, argv, label, *, deadline, clock):
|
||||
cwd = Path.cwd().resolve()
|
||||
kwargs = {
|
||||
"cwd": cwd,
|
||||
"capture_output": True,
|
||||
"check": False,
|
||||
"shell": False,
|
||||
}
|
||||
remaining = _remaining(deadline, clock, label)
|
||||
if remaining is not None:
|
||||
kwargs["timeout"] = remaining
|
||||
try:
|
||||
return run(argv, **kwargs)
|
||||
except subprocess.TimeoutExpired as exc:
|
||||
raise ToolchainError(
|
||||
f"{label} probe timed out; argv={argv!r}; cwd={str(cwd)!r}; "
|
||||
"install or repair Visual Studio Desktop development with C++"
|
||||
) from exc
|
||||
|
||||
|
||||
def discover_toolchain(
|
||||
kind: ProjectKind,
|
||||
*,
|
||||
env=None,
|
||||
which=shutil.which,
|
||||
run=subprocess.run,
|
||||
deadline=None,
|
||||
clock=time.monotonic,
|
||||
) -> Toolchain:
|
||||
environment = os.environ if env is None else env
|
||||
vswhere_path = which("vswhere.exe")
|
||||
if vswhere_path is None:
|
||||
program_files = environment.get("ProgramFiles(x86)")
|
||||
if program_files:
|
||||
candidate = Path(program_files) / "Microsoft Visual Studio/Installer/vswhere.exe"
|
||||
vswhere_path = str(candidate) if candidate.exists() else None
|
||||
vswhere = _require_path(
|
||||
Path(vswhere_path) if vswhere_path else None,
|
||||
"vswhere.exe; install Visual Studio Desktop development with C++",
|
||||
)
|
||||
|
||||
install_argv = [
|
||||
str(vswhere), "-latest", "-products", "*", "-requires", VC_WORKLOAD,
|
||||
"-property", "installationPath",
|
||||
]
|
||||
install_result = _probe(
|
||||
run,
|
||||
install_argv,
|
||||
"Visual Studio installation",
|
||||
deadline=deadline,
|
||||
clock=clock,
|
||||
)
|
||||
probe_cwd = Path.cwd().resolve()
|
||||
installation = _require_path(
|
||||
_first_path(
|
||||
install_result,
|
||||
"Visual Studio installation",
|
||||
install_argv,
|
||||
probe_cwd,
|
||||
),
|
||||
"Visual Studio installation",
|
||||
)
|
||||
msbuild_argv = [
|
||||
str(vswhere), "-latest", "-products", "*", "-requires", VC_WORKLOAD,
|
||||
"-find", r"MSBuild\**\Bin\MSBuild.exe",
|
||||
]
|
||||
msbuild_result = _probe(
|
||||
run,
|
||||
msbuild_argv,
|
||||
"MSBuild",
|
||||
deadline=deadline,
|
||||
clock=clock,
|
||||
)
|
||||
msbuild = _require_path(
|
||||
_first_path(msbuild_result, "MSBuild", msbuild_argv, probe_cwd),
|
||||
"MSBuild.exe",
|
||||
)
|
||||
|
||||
if kind is not ProjectKind.CMAKE:
|
||||
return Toolchain(installation=installation, msbuild=msbuild)
|
||||
|
||||
bundled_cmake_dir = installation / VS_CMAKE_RELATIVE
|
||||
cmake = _require_path(
|
||||
Path(which("cmake.exe")) if which("cmake.exe") else bundled_cmake_dir / "cmake.exe",
|
||||
"cmake.exe",
|
||||
)
|
||||
ctest = _require_path(
|
||||
Path(which("ctest.exe")) if which("ctest.exe") else bundled_cmake_dir / "ctest.exe",
|
||||
"ctest.exe",
|
||||
)
|
||||
return Toolchain(installation=installation, msbuild=msbuild, cmake=cmake, ctest=ctest)
|
||||
Reference in New Issue
Block a user