Skip to content

Commit 46bca69

Browse files
CybotTMclaude
andcommitted
refactor(detection): use catalog version_args instead of hardcoded special cases
- Add version_args field to catalog/*.json for custom version detection - Implement ToolCatalog.has_tool() and get_raw_data() methods - Pass version_args from catalog to detection functions - Remove hardcoded curlie version detection special case - Add version_args: ["version"] to catalog/curlie.json This makes version detection more maintainable by moving tool-specific detection logic from Python code to catalog metadata. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 2443340 commit 46bca69

4 files changed

Lines changed: 45 additions & 18 deletions

File tree

audit.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,18 @@ def audit_tool(tool: Tool, offline_cache: dict[str, tuple[str, str]] | None = No
121121
Returns:
122122
Dictionary with audit results
123123
"""
124+
# Load catalog metadata for version detection
125+
from cli_audit.catalog import ToolCatalog
126+
catalog = ToolCatalog()
127+
version_args = None
128+
if catalog.has_tool(tool.name):
129+
catalog_data = catalog.get_raw_data(tool.name)
130+
version_args = catalog_data.get("version_args")
131+
124132
# Detect installed version
125133
deep_scan = tool.name in {"node", "python", "semgrep", "pre-commit", "bandit", "black", "flake8", "isort"}
126134
version_num, version_line, path, install_method = audit_tool_installation(
127-
tool.name, tool.candidates, deep=deep_scan
135+
tool.name, tool.candidates, deep=deep_scan, version_args=version_args
128136
)
129137

130138
installed = version_num if version_num else (version_line if version_line != "X" else "")

catalog/curlie.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"homepage": "https://github.com/rs/curlie",
66
"github_repo": "rs/curlie",
77
"binary_name": "curlie",
8+
"version_args": ["version"],
89
"download_url_template": "https://github.com/rs/curlie/releases/download/{version}/curlie_{version_nov}_linux_{arch}.tar.gz",
910
"arch_map": {
1011
"x86_64": "amd64",

cli_audit/catalog.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ def __init__(self, catalog_dir: str | Path | None = None):
6262
self.catalog_dir = Path(catalog_dir)
6363

6464
self._entries: dict[str, ToolCatalogEntry] = {}
65+
self._raw_data: dict[str, dict[str, Any]] = {}
6566
self._load_catalog()
6667

6768
def _load_catalog(self) -> None:
@@ -76,6 +77,7 @@ def _load_catalog(self) -> None:
7677
data = json.load(f)
7778
entry = ToolCatalogEntry.from_dict(data)
7879
self._entries[entry.name] = entry
80+
self._raw_data[entry.name] = data # Store raw JSON
7981
logger.debug(f"Loaded catalog entry: {entry.name}")
8082
except Exception as e:
8183
logger.error(f"Failed to load {json_file}: {e}")
@@ -93,6 +95,28 @@ def get(self, tool_name: str) -> ToolCatalogEntry | None:
9395
"""
9496
return self._entries.get(tool_name)
9597

98+
def has_tool(self, tool_name: str) -> bool:
99+
"""Check if a tool exists in the catalog.
100+
101+
Args:
102+
tool_name: Tool name
103+
104+
Returns:
105+
True if tool exists in catalog
106+
"""
107+
return tool_name in self._entries
108+
109+
def get_raw_data(self, tool_name: str) -> dict[str, Any]:
110+
"""Get raw JSON data for a tool.
111+
112+
Args:
113+
tool_name: Tool name
114+
115+
Returns:
116+
Raw catalog JSON data or empty dict if not found
117+
"""
118+
return self._raw_data.get(tool_name, {})
119+
96120
def is_pinned(self, tool_name: str) -> bool:
97121
"""Check if a tool has a pinned version.
98122

cli_audit/detection.py

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -144,16 +144,23 @@ def extract_version_number(s: str) -> str:
144144
return m2.group(1) if m2 else ""
145145

146146

147-
def get_version_line(path: str, tool_name: str) -> str:
147+
def get_version_line(path: str, tool_name: str, version_args: list[str] | None = None) -> str:
148148
"""Get version string for installed tool.
149149
150150
Args:
151151
path: Path to executable
152152
tool_name: Tool name for special-case handling
153+
version_args: Custom version arguments from catalog (e.g., ["version"])
153154
154155
Returns:
155156
Version line string or empty string
156157
"""
158+
# If catalog specifies custom version args, use them first
159+
if version_args:
160+
line = run_with_timeout([path] + version_args)
161+
if line:
162+
return line
163+
157164
# Special cases
158165
if tool_name == "go":
159166
line = run_with_timeout([path, "version"])
@@ -202,20 +209,6 @@ def get_version_line(path: str, tool_name: str) -> str:
202209
except Exception:
203210
pass
204211

205-
if tool_name == "curlie":
206-
# Real curlie uses "curlie version" subcommand (no dashes)
207-
# Output: "curlie 1.8.2 (2025-03-07T08:52:36Z)"
208-
line = run_with_timeout([path, "version"])
209-
if line and "curlie" in line.lower():
210-
# Real curlie binary
211-
return line
212-
213-
# Fallback: try --version for apt/distro curl symlink
214-
line = run_with_timeout([path, "--version"])
215-
if line and "curl" in line.lower() and "curlie" not in line.lower():
216-
# Fake curlie (apt/distro package) - mark as wrong binary
217-
return "CONFLICT: apt curl masquerading as curlie"
218-
return ""
219212

220213
if tool_name == "fx":
221214
# fx is a Node.js tool with no --version flag
@@ -329,14 +322,15 @@ def choose_highest(candidates: list[tuple[str, str, str]]) -> tuple[str, str, st
329322

330323

331324
def audit_tool_installation(
332-
tool_name: str, candidates: tuple[str, ...], deep: bool = False
325+
tool_name: str, candidates: tuple[str, ...], deep: bool = False, version_args: list[str] | None = None
333326
) -> tuple[str, str, str, str]:
334327
"""Audit a single tool's installation.
335328
336329
Args:
337330
tool_name: Tool name
338331
candidates: Binary names to search for
339332
deep: If True, find all installations
333+
version_args: Custom version arguments from catalog (e.g., ["version"])
340334
341335
Returns:
342336
Tuple of (version_num, version_line, path, install_method)
@@ -345,7 +339,7 @@ def audit_tool_installation(
345339

346340
for cand in candidates:
347341
for path in find_paths(cand, deep=deep):
348-
line = get_version_line(path, tool_name)
342+
line = get_version_line(path, tool_name, version_args)
349343
if line:
350344
num = extract_version_number(line)
351345
tuples.append((num, line, path))

0 commit comments

Comments
 (0)