Skip to content

Commit c38ab18

Browse files
committed
PR #1155: Install wheel assets when present and verify checksums
- Add download_and_install_wheel_asset() helper - Prefer release wheel assets for non-Windows installs and verify SHA256 - Fallback to pip install when no wheel asset is available
1 parent 3f110f3 commit c38ab18

File tree

2 files changed

+64
-0
lines changed

2 files changed

+64
-0
lines changed

ardupilot_methodic_configurator/backend_internet.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,54 @@ def _compute_sha256(path: str) -> str:
400400
return h.hexdigest()
401401

402402

403+
def download_and_install_wheel_asset(
404+
download_url: str,
405+
file_name: str,
406+
expected_sha256: Optional[str] = None,
407+
progress_callback: Optional[Callable[[float, str], None]] = None,
408+
) -> int:
409+
"""Download a wheel asset, verify SHA256 if provided, and install via pip."""
410+
logging_info(_("Downloading wheel asset for installation..."))
411+
412+
try:
413+
with tempfile.TemporaryDirectory() as temp_dir:
414+
temp_path = os.path.join(temp_dir, file_name)
415+
416+
if not download_file_from_url(
417+
download_url,
418+
temp_path,
419+
timeout=120,
420+
progress_callback=progress_callback,
421+
):
422+
logging_error(_("Failed to download wheel from %s"), download_url)
423+
return 1
424+
425+
if expected_sha256:
426+
actual = _compute_sha256(temp_path)
427+
if actual.lower() != expected_sha256.lower():
428+
logging_error(_("SHA256 mismatch for wheel: expected %s got %s"), expected_sha256, actual)
429+
try:
430+
os.remove(temp_path)
431+
except OSError:
432+
pass
433+
return 1
434+
435+
# Install the wheel file
436+
ret = subprocess.check_call([sys.executable, "-m", "pip", "install", "--upgrade", temp_path])
437+
438+
if ret == 0 and progress_callback:
439+
progress_callback(100.0, _("Installation complete"))
440+
441+
return ret
442+
443+
except subprocess.CalledProcessError as e:
444+
logging_error(_("Wheel installation failed: %s"), e)
445+
return 1
446+
except Exception as e: # pylint: disable=broad-exception-caught
447+
logging_error(_("Unexpected error installing wheel: %s"), e)
448+
return 1
449+
450+
403451
def verify_and_open_url(url: str) -> bool:
404452
"""
405453
Verify if a URL is accessible and open it in the default web browser if successful.

ardupilot_methodic_configurator/data_model_software_updates.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
from ardupilot_methodic_configurator.backend_internet import (
3030
download_and_install_on_windows,
3131
download_and_install_pip_release,
32+
download_and_install_wheel_asset,
3233
get_release_info,
3334
get_expected_sha256_from_release,
3435
webbrowser_open_url,
@@ -93,6 +94,21 @@ def _perform_download(self, latest_release: dict[str, Any]) -> bool:
9394
return False
9495

9596
try:
97+
# Prefer wheel assets included in the GitHub release if available
98+
wheel_assets = [a for a in latest_release.get("assets", []) if a.get("name", "").lower().endswith(".whl")]
99+
if wheel_assets:
100+
wheel = wheel_assets[0]
101+
expected_sha256 = get_expected_sha256_from_release(latest_release, wheel["name"])
102+
return (
103+
download_and_install_wheel_asset(
104+
download_url=wheel["browser_download_url"],
105+
file_name=wheel["name"],
106+
expected_sha256=expected_sha256,
107+
progress_callback=self.dialog.update_progress if self.dialog else None,
108+
)
109+
== 0
110+
)
111+
96112
return (
97113
download_and_install_pip_release(progress_callback=self.dialog.update_progress if self.dialog else None) == 0
98114
)

0 commit comments

Comments
 (0)