refactor(pyghidra_launcher): Improve get_package_version implementation

Refactors the `get_package_version` helper function to use the standard
`importlib.metadata` library instead of a subprocess call to `pip show`.

This change provides several benefits:
- Robustness: Avoids brittle parsing of command-line tool output.
- Performance: Eliminates the overhead of spawning a new process.
- Correctness: The return type hint is corrected to `Optional[str]` to
  accurately reflect that the function can return `None`.
- Simplicity: The unused `python_cmd` parameter has been removed,
  simplifying the function's signature.
This commit is contained in:
jhq223
2025-10-25 18:18:05 +08:00
parent 4e4a14f0d1
commit 8148f6364f

View File

@@ -21,7 +21,8 @@ import subprocess
import sysconfig import sysconfig
from pathlib import Path from pathlib import Path
from itertools import chain from itertools import chain
from typing import List, Dict, Tuple from importlib import metadata
from typing import List, Dict, Tuple, Optional
def get_application_properties(install_dir: Path) -> Dict[str, str]: def get_application_properties(install_dir: Path) -> Dict[str, str]:
app_properties_path: Path = install_dir / 'Ghidra' / 'application.properties' app_properties_path: Path = install_dir / 'Ghidra' / 'application.properties'
@@ -137,16 +138,14 @@ def version_tuple(v: str) -> Tuple[str, ...]:
filled.append(point.zfill(8)) filled.append(point.zfill(8))
return tuple(filled) return tuple(filled)
def get_package_version(python_cmd: List[str], package: str) -> str: def get_package_version(package: str) -> Optional[str]:
version = None """
result = subprocess.run(python_cmd + ['-m', 'pip', 'show', package], capture_output=True, text=True) Checks for an installed package version.
for line in result.stdout.splitlines(): """
line = line.strip() try:
print(line) return metadata.version(package)
key, value = line.split(':', 1) except metadata.PackageNotFoundError:
if key == 'Version': return None
version = value.strip()
return version
def get_saved_python_cmd(install_dir: Path, dev: bool) -> List[str]: def get_saved_python_cmd(install_dir: Path, dev: bool) -> List[str]:
user_settings_dir: Path = get_user_settings_dir(install_dir, dev) user_settings_dir: Path = get_user_settings_dir(install_dir, dev)
@@ -269,7 +268,7 @@ def main() -> None:
# If PyGhidra is not installed in the execution environment, offer to install it # If PyGhidra is not installed in the execution environment, offer to install it
# If it's already installed, offer to upgrade (if applicable) # If it's already installed, offer to upgrade (if applicable)
current_pyghidra_version = get_package_version(python_cmd, 'pyghidra') current_pyghidra_version = get_package_version('pyghidra')
if current_pyghidra_version is None: if current_pyghidra_version is None:
python_cmd = install(install_dir, python_cmd, pip_args, offer_venv) python_cmd = install(install_dir, python_cmd, pip_args, offer_venv)
if not python_cmd: if not python_cmd:
@@ -289,6 +288,6 @@ def main() -> None:
else: else:
creation_flags = getattr(subprocess, 'CREATE_NO_WINDOW', 0) creation_flags = getattr(subprocess, 'CREATE_NO_WINDOW', 0)
subprocess.Popen(py_args + remaining, creationflags=creation_flags, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) subprocess.Popen(py_args + remaining, creationflags=creation_flags, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
if __name__ == "__main__": if __name__ == "__main__":
main() main()