-
-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathutil.py
More file actions
103 lines (83 loc) · 3.31 KB
/
util.py
File metadata and controls
103 lines (83 loc) · 3.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import sys
import shutil
import subprocess
from pathlib import Path
import logging
from typing import Optional, List
if sys.version_info >= (3, 11):
import tomllib
else:
import tomli as tomllib
from cpp_linter_hooks.versions import CLANG_FORMAT_VERSIONS, CLANG_TIDY_VERSIONS
LOG = logging.getLogger(__name__)
def get_version_from_dependency(tool: str) -> Optional[str]:
"""Get the version of a tool from the pyproject.toml dependencies."""
pyproject_path = Path(__file__).parent.parent / "pyproject.toml"
if not pyproject_path.exists():
return None
with open(pyproject_path, "rb") as f:
data = tomllib.load(f)
# Check [project].dependencies
dependencies = data.get("project", {}).get("dependencies", [])
for dep in dependencies:
if dep.startswith(f"{tool}=="):
return dep.split("==")[1]
return None
DEFAULT_CLANG_FORMAT_VERSION = CLANG_FORMAT_VERSIONS[-1] # latest from versions.py
DEFAULT_CLANG_TIDY_VERSION = CLANG_TIDY_VERSIONS[-1] # latest from versions.py
def _resolve_version(versions: List[str], user_input: Optional[str]) -> Optional[str]:
"""Resolve the latest matching version based on user input and available versions."""
if user_input is None:
return None
if user_input in versions:
return user_input
try:
# filter versions that start with the user input
matched_versions = [v for v in versions if v.startswith(user_input)]
if not matched_versions:
raise ValueError
# define a function to parse version strings into tuples for comparison
def parse_version(v: str):
return tuple(map(int, v.split(".")))
# return the latest version
return max(matched_versions, key=parse_version)
except ValueError:
LOG.warning("Version %s not found in available versions", user_input)
return None
def _is_version_installed(tool: str, version: str) -> Optional[Path]:
"""Return the tool path if the installed version matches, otherwise None."""
existing = shutil.which(tool)
if not existing:
return None
result = subprocess.run([existing, "--version"], capture_output=True, text=True)
if version in result.stdout:
return Path(existing)
return None
def _install_tool(tool: str, version: str) -> Optional[Path]:
"""Install a tool using pip, logging output on failure."""
result = subprocess.run(
[sys.executable, "-m", "pip", "install", f"{tool}=={version}"],
capture_output=True,
text=True,
)
if result.returncode == 0:
return shutil.which(tool)
LOG.error("pip failed to install %s %s", tool, version)
LOG.error(result.stdout)
LOG.error(result.stderr)
return None
def resolve_install(tool: str, version: Optional[str]) -> Optional[Path]:
"""Resolve the installation of a tool, checking for version and installing if necessary."""
user_version = _resolve_version(
CLANG_FORMAT_VERSIONS if tool == "clang-format" else CLANG_TIDY_VERSIONS,
version,
)
if user_version is None:
user_version = (
DEFAULT_CLANG_FORMAT_VERSION
if tool == "clang-format"
else DEFAULT_CLANG_TIDY_VERSION
)
return _is_version_installed(tool, user_version) or _install_tool(
tool, user_version
)