ida-hcli 0.13.3.dev2__tar.gz → 0.13.3.dev4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/PKG-INFO +1 -1
  2. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/pyproject.toml +1 -1
  3. ida_hcli-0.13.3.dev4/src/hcli/__init__.py +1 -0
  4. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/plugin/lint.py +31 -10
  5. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/ida/__init__.py +17 -4
  6. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/ida/plugin/repo/github.py +31 -25
  7. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/ida/python.py +5 -1
  8. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/ida_hcli.egg-info/PKG-INFO +1 -1
  9. ida_hcli-0.13.3.dev2/src/hcli/__init__.py +0 -1
  10. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/LICENSE +0 -0
  11. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/README.md +0 -0
  12. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/setup.cfg +0 -0
  13. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/__init__.py +0 -0
  14. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/auth/__init__.py +0 -0
  15. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/auth/default.py +0 -0
  16. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/auth/key/__init__.py +0 -0
  17. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/auth/key/create.py +0 -0
  18. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/auth/key/install.py +0 -0
  19. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/auth/key/list.py +0 -0
  20. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/auth/key/revoke.py +0 -0
  21. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/auth/list.py +0 -0
  22. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/auth/switch.py +0 -0
  23. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/commands.py +0 -0
  24. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/common.py +0 -0
  25. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/download.py +0 -0
  26. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/extension/__init__.py +0 -0
  27. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/extension/create.py +0 -0
  28. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/extension/list.py +0 -0
  29. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/ida/__init__.py +0 -0
  30. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/ida/install.py +0 -0
  31. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/ida/set_default.py +0 -0
  32. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/ke/__init__.py +0 -0
  33. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/ke/ida/__init__.py +0 -0
  34. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/ke/ida/add.py +0 -0
  35. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/ke/ida/list.py +0 -0
  36. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/ke/ida/remove.py +0 -0
  37. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/ke/ida/switch.py +0 -0
  38. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/ke/open.py +0 -0
  39. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/ke/setup.py +0 -0
  40. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/ke/source/__init__.py +0 -0
  41. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/ke/source/add.py +0 -0
  42. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/ke/source/list.py +0 -0
  43. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/ke/source/remove.py +0 -0
  44. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/license/__init__.py +0 -0
  45. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/license/common.py +0 -0
  46. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/license/get.py +0 -0
  47. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/license/install.py +0 -0
  48. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/license/list.py +0 -0
  49. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/login.py +0 -0
  50. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/logout.py +0 -0
  51. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/plugin/__init__.py +0 -0
  52. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/plugin/config.py +0 -0
  53. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/plugin/install.py +0 -0
  54. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/plugin/repo.py +0 -0
  55. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/plugin/search.py +0 -0
  56. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/plugin/status.py +0 -0
  57. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/plugin/uninstall.py +0 -0
  58. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/plugin/upgrade.py +0 -0
  59. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/share/__init__.py +0 -0
  60. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/share/delete.py +0 -0
  61. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/share/get.py +0 -0
  62. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/share/list.py +0 -0
  63. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/share/put.py +0 -0
  64. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/update.py +0 -0
  65. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/commands/whoami.py +0 -0
  66. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/env.py +0 -0
  67. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/__init__.py +0 -0
  68. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/api/__init__.py +0 -0
  69. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/api/asset.py +0 -0
  70. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/api/auth.py +0 -0
  71. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/api/common.py +0 -0
  72. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/api/customer.py +0 -0
  73. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/api/index.py +0 -0
  74. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/api/keys.py +0 -0
  75. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/api/license.py +0 -0
  76. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/auth/__init__.py +0 -0
  77. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/commands/__init__.py +0 -0
  78. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/config/__init__.py +0 -0
  79. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/console.py +0 -0
  80. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/constants/__init__.py +0 -0
  81. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/constants/auth.py +0 -0
  82. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/constants/cli.py +0 -0
  83. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/extensions/__init__.py +0 -0
  84. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/ida/plugin/__init__.py +0 -0
  85. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/ida/plugin/exceptions.py +0 -0
  86. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/ida/plugin/install.py +0 -0
  87. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/ida/plugin/repo/__init__.py +0 -0
  88. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/ida/plugin/repo/file.py +0 -0
  89. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/ida/plugin/repo/fs.py +0 -0
  90. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/ida/plugin/settings.py +0 -0
  91. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/ida/protocol.py +0 -0
  92. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/update/__init__.py +0 -0
  93. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/update/release.py +0 -0
  94. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/update/version.py +0 -0
  95. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/util/__init__.py +0 -0
  96. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/util/cache.py +0 -0
  97. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/util/crc32.py +0 -0
  98. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/util/io.py +0 -0
  99. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/util/logging.py +0 -0
  100. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/util/output.py +0 -0
  101. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/util/python.py +0 -0
  102. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/lib/util/string.py +0 -0
  103. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/hcli/main.py +0 -0
  104. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/ida_hcli.egg-info/SOURCES.txt +0 -0
  105. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/ida_hcli.egg-info/dependency_links.txt +0 -0
  106. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/ida_hcli.egg-info/entry_points.txt +0 -0
  107. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/ida_hcli.egg-info/requires.txt +0 -0
  108. {ida_hcli-0.13.3.dev2 → ida_hcli-0.13.3.dev4}/src/ida_hcli.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ida-hcli
3
- Version: 0.13.3.dev2
3
+ Version: 0.13.3.dev4
4
4
  Summary: HCLI - Hex-Rays CLI Utility
5
5
  Author-email: Hex-Rays SA <support@hex-rays.com>
6
6
  License-Expression: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ida-hcli"
3
- version = "0.13.3-dev.2"
3
+ version = "0.13.3-dev.4"
4
4
  description = "HCLI - Hex-Rays CLI Utility"
5
5
  requires-python = ">=3.10"
6
6
  license = "MIT"
@@ -0,0 +1 @@
1
+ __version__ = "0.13.3-dev.4"
@@ -14,12 +14,12 @@ from pydantic import ValidationError
14
14
  from hcli.lib.console import console
15
15
  from hcli.lib.ida.plugin import (
16
16
  IDAMetadataDescriptor,
17
- get_metadatas_with_paths_from_plugin_archive,
18
17
  parse_plugin_version,
19
18
  validate_metadata_in_plugin_archive,
20
19
  )
21
20
  from hcli.lib.ida.plugin.install import validate_metadata_in_plugin_directory
22
21
  from hcli.lib.ida.plugin.repo import fetch_plugin_archive
22
+ from hcli.lib.util.logging import m
23
23
 
24
24
  logger = logging.getLogger(__name__)
25
25
 
@@ -232,15 +232,36 @@ def _lint_plugin_archive(zip_data: bytes, source_name: str) -> int:
232
232
  """
233
233
  recommendation_count = 0
234
234
 
235
- try:
236
- plugins_found = list(get_metadatas_with_paths_from_plugin_archive(zip_data))
237
- except Exception as e:
238
- console.print(f"[red]Error[/red]: Failed to read plugins from archive {source_name}: {e}")
239
- recommendation_count += 1
240
- return recommendation_count
241
- else:
242
- for path, meta in plugins_found:
243
- logger.debug("found plugin %s at %s", meta.plugin.name, path)
235
+ plugins_found = []
236
+ with zipfile.ZipFile(io.BytesIO(zip_data), "r") as zip_file:
237
+ for file_path in zip_file.namelist():
238
+ if not file_path.endswith("ida-plugin.json"):
239
+ continue
240
+
241
+ logger.debug(m("found metadata path: %s", file_path))
242
+ with zip_file.open(file_path) as f:
243
+ try:
244
+ metadata = IDAMetadataDescriptor.model_validate_json(f.read().decode("utf-8"))
245
+ except ValidationError as e:
246
+ logger.debug(m("failed to validate metadata: %s", file_path, path=file_path, error=str(e)))
247
+ console.print(f"[red]Error[/red] ({source_name}): {file_path}: ida-plugin.json validation failed")
248
+ for error in e.errors():
249
+ field_path = ".".join(str(loc) for loc in error["loc"])
250
+ error_msg = error["msg"]
251
+ error_type = error["type"]
252
+
253
+ if error_type == "missing":
254
+ console.print(f" [red]Missing required field[/red]: {field_path}")
255
+ else:
256
+ console.print(f" [red]Invalid value[/red] for {field_path}: {error_msg}")
257
+ recommendation_count += 1
258
+ continue
259
+ else:
260
+ logger.debug(m("found valid metadata: %s", file_path))
261
+ plugins_found.append((Path(file_path), metadata))
262
+
263
+ for path, meta in plugins_found:
264
+ logger.debug("found plugin %s at %s", meta.plugin.name, path)
244
265
 
245
266
  if not plugins_found:
246
267
  console.print(f"[red]Error[/red]: No valid plugins found in archive {source_name}")
@@ -176,6 +176,8 @@ def get_default_ida_install_directory(ver: IdaProduct) -> Path:
176
176
  # typically idat isn't widely used; however, HCLI does use it to discover the path to IDA's Python interpreter,
177
177
  # as well as the installed arch (ARM or Intel on macOS). The latter could probably be discovered by inspecting
178
178
  # the installed files; however, figuring out the Python configuration is messy, and much easier to leave to idat.
179
+ #
180
+ # see also the warnings in commands/ida/install.py.
179
181
  if ver.major == 9 and ver.minor == 2 and " " in app_directory_name:
180
182
  # "IDA Professional 9.2" -> "IDA-Professional-9.2"
181
183
  sanitized_name = app_directory_name.replace(" ", "-")
@@ -624,6 +626,11 @@ def run_py_in_current_idapython(src: str) -> str:
624
626
  if not idat_path.exists():
625
627
  raise ValueError(f"can't find idat: {idat_path}")
626
628
 
629
+ if get_os() == "linux" and "9.2" in str(idat_path.absolute()):
630
+ logger.warning(
631
+ "invoking idat on IDA 9.2/Linux with a space in the full path, you might encounter HCLI GitHub issue #99"
632
+ )
633
+
627
634
  with tempfile.TemporaryDirectory() as temp_dir:
628
635
  temp_path = Path(temp_dir)
629
636
 
@@ -661,7 +668,7 @@ def run_py_in_current_idapython(src: str) -> str:
661
668
  logger.debug(f"idat stderr: {result.stderr}")
662
669
 
663
670
  if not log_path.exists():
664
- raise RuntimeError(f"Log file was not created: {log_path}")
671
+ raise RuntimeError(f"failed to invoke idat: log file was not created: {log_path}")
665
672
 
666
673
  for line in log_path.read_text().splitlines():
667
674
  if not line.startswith("__hcli__:"):
@@ -669,7 +676,7 @@ def run_py_in_current_idapython(src: str) -> str:
669
676
 
670
677
  return json.loads(line[len("__hcli__:") :])
671
678
 
672
- raise RuntimeError("Could not find __hcli__: prefix in log output")
679
+ raise RuntimeError("failed to invoke idat: could not find expected lines in log output")
673
680
 
674
681
 
675
682
  def get_current_ida_platform_cache_path() -> Path:
@@ -745,7 +752,10 @@ def find_current_ida_platform() -> str:
745
752
  return get_current_ida_platform_cache(ida_dir)
746
753
  except KeyError:
747
754
  pass
748
- platform = run_py_in_current_idapython(FIND_PLATFORM_PY)
755
+ try:
756
+ platform = run_py_in_current_idapython(FIND_PLATFORM_PY)
757
+ except RuntimeError as e:
758
+ raise RuntimeError("failed to determine current IDA platform") from e
749
759
  set_current_ida_platform_cache(ida_dir, platform)
750
760
  return platform
751
761
  else:
@@ -802,7 +812,10 @@ def find_current_ida_version() -> str:
802
812
  return get_current_ida_version_cache(ida_dir)
803
813
  except KeyError:
804
814
  pass
805
- version = run_py_in_current_idapython(FIND_VERSION_PY)
815
+ try:
816
+ version = run_py_in_current_idapython(FIND_VERSION_PY)
817
+ except RuntimeError as e:
818
+ raise RuntimeError("failed to determine current IDA version") from e
806
819
  set_current_ida_version_cache(ida_dir, version)
807
820
  return version
808
821
 
@@ -634,8 +634,14 @@ class GithubPluginRepo(BasePluginRepo):
634
634
  md = get_releases_metadata(self.client, owner, repo)
635
635
  seen_zipball_urls = set()
636
636
  for release in md.releases:
637
+ context = {
638
+ "owner": owner,
639
+ "repo": repo,
640
+ "release": release.tag_name,
641
+ "date": release.published_at,
642
+ }
637
643
  logger.debug(
638
- m("considering release: %s", release.tag_name, owner=owner, repo=repo, release=release.tag_name)
644
+ m("considering release: %s", release.tag_name, **context)
639
645
  )
640
646
 
641
647
  if release.published_at < "2025-09-01":
@@ -643,20 +649,18 @@ class GithubPluginRepo(BasePluginRepo):
643
649
  m(
644
650
  "skipping old release: %s < 2025-09-01",
645
651
  release.published_at,
646
- owner=owner,
647
- repo=repo,
648
- release=release.tag_name,
652
+ **context,
649
653
  )
650
654
  )
651
655
  continue
652
656
 
653
- logger.debug(m("found release: %s", release.tag_name, owner=owner, repo=repo, release=release.tag_name))
657
+ logger.debug(m("found release: %s", release.tag_name, **context))
654
658
 
655
659
  # source archives
656
- source_archives.append((owner, repo, release.commit_hash, release.zipball_url))
660
+ source_archives.append((owner, repo, release.commit_hash, release.zipball_url, release.published_at))
657
661
  seen_zipball_urls.add(release.zipball_url)
658
662
  logger.debug(
659
- m("found zipball URL: %s", release.zipball_url, owner=owner, repo=repo, release=release.tag_name)
663
+ m("found zipball URL: %s", release.zipball_url, **context)
660
664
  )
661
665
 
662
666
  # assets (distribution/binary archives)
@@ -664,23 +668,27 @@ class GithubPluginRepo(BasePluginRepo):
664
668
  if asset.content_type != "application/zip":
665
669
  continue
666
670
 
667
- assets.append((owner, repo, release.tag_name, asset))
671
+ assets.append((owner, repo, release.tag_name, asset, release.published_at))
668
672
  logger.debug(
669
673
  m(
670
674
  "found zip asset: %s",
671
675
  asset.download_url,
672
- owner=owner,
673
- repo=repo,
674
- release=release.tag_name,
675
- asset=asset.name,
676
+ **dict(context, asset=asset.name),
676
677
  )
677
678
  )
678
679
 
679
680
  for tag in md.tags:
680
- logger.debug(m("considering tag: %s", tag.tag_name, owner=owner, repo=repo, tag=tag.tag_name))
681
+ context = {
682
+ "owner": owner,
683
+ "repo": repo,
684
+ "tag": tag.tag_name,
685
+ "date": tag.committed_date,
686
+ }
687
+
688
+ logger.debug(m("considering tag: %s", tag.tag_name, **context))
681
689
 
682
690
  if not tag.tag_name.startswith("v"):
683
- logger.debug(m("skipping non-v* tag: %s", tag.tag_name, owner=owner, repo=repo, tag=tag.tag_name))
691
+ logger.debug(m("skipping non-v* tag: %s", tag.tag_name, **context))
684
692
  continue
685
693
 
686
694
  if tag.committed_date < "2025-09-01":
@@ -688,27 +696,25 @@ class GithubPluginRepo(BasePluginRepo):
688
696
  m(
689
697
  "skipping old tag: %s < 2025-09-01",
690
698
  tag.committed_date,
691
- owner=owner,
692
- repo=repo,
693
- tag=tag.tag_name,
699
+ **context,
694
700
  )
695
701
  )
696
702
  continue
697
703
 
698
- logger.debug(m("found tag: %s", tag.tag_name, owner=owner, repo=repo, tag=tag.tag_name))
704
+ logger.debug(m("found tag: %s", tag.tag_name, **context))
699
705
 
700
706
  if tag.zipball_url in seen_zipball_urls:
701
707
  logger.debug(
702
- m("already found URL for tag: %s", tag.zipball_url, owner=owner, repo=repo, tag=tag.tag_name)
708
+ m("already found URL for tag: %s", tag.zipball_url, **context)
703
709
  )
704
710
  else:
705
- source_archives.append((owner, repo, tag.commit_hash, tag.zipball_url))
711
+ source_archives.append((owner, repo, tag.commit_hash, tag.zipball_url, tag.committed_date))
706
712
  seen_zipball_urls.add(tag.zipball_url)
707
- logger.debug(m("found zipball URL: %s", tag.zipball_url, owner=owner, repo=repo, tag=tag.tag_name))
713
+ logger.debug(m("found zipball URL: %s", tag.zipball_url, **context))
708
714
 
709
715
  index = PluginArchiveIndex()
710
716
 
711
- for owner, repo, tag_name, asset in rich.progress.track(
717
+ for owner, repo, tag_name, asset, date in rich.progress.track(
712
718
  assets, description="Fetching plugin assests", transient=True, console=stderr_console
713
719
  ):
714
720
  logger.debug(m("fetching release asset: %s", asset.download_url, owner=owner, repo=repo, tag=tag_name))
@@ -722,10 +728,10 @@ class GithubPluginRepo(BasePluginRepo):
722
728
  buf,
723
729
  asset.download_url,
724
730
  expected_host=host_url,
725
- context=dict(owner=owner, repo=repo, type="release asset", tag=tag_name, url=asset.download_url),
731
+ context=dict(owner=owner, repo=repo, type="release asset", tag=tag_name, url=asset.download_url, date=date),
726
732
  )
727
733
 
728
- for owner, repo, commit_hash, url in rich.progress.track(
734
+ for owner, repo, commit_hash, url, date in rich.progress.track(
729
735
  source_archives, description="Fetching plugin source archives", transient=True, console=stderr_console
730
736
  ):
731
737
  logger.debug(m("fetching source archive: %s", url, owner=owner, repo=repo, commit=commit_hash))
@@ -739,7 +745,7 @@ class GithubPluginRepo(BasePluginRepo):
739
745
  buf,
740
746
  url,
741
747
  expected_host=host_url,
742
- context=dict(owner=owner, repo=repo, type="source archive", commit=commit_hash, url=url),
748
+ context=dict(owner=owner, repo=repo, type="source archive", commit=commit_hash, url=url, date=date),
743
749
  )
744
750
 
745
751
  return index.get_plugins()
@@ -32,7 +32,11 @@ def find_current_python_executable() -> Path:
32
32
  if ENV.HCLI_CURRENT_IDA_PYTHON_EXE is not None:
33
33
  return Path(ENV.HCLI_CURRENT_IDA_PYTHON_EXE)
34
34
 
35
- exe = run_py_in_current_idapython(FIND_PYTHON_PY)
35
+ try:
36
+ exe = run_py_in_current_idapython(FIND_PYTHON_PY)
37
+ except RuntimeError as e:
38
+ raise RuntimeError("failed to determine current IDA python interpreter") from e
39
+
36
40
  logger.debug("found python path: %s", exe)
37
41
  return Path(exe)
38
42
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ida-hcli
3
- Version: 0.13.3.dev2
3
+ Version: 0.13.3.dev4
4
4
  Summary: HCLI - Hex-Rays CLI Utility
5
5
  Author-email: Hex-Rays SA <support@hex-rays.com>
6
6
  License-Expression: MIT
@@ -1 +0,0 @@
1
- __version__ = "0.13.3-dev.2"
File without changes
File without changes
File without changes