Skip to content

Commit

Permalink
Feat : Add download update feature in user app. Issue #755
Browse files Browse the repository at this point in the history
  • Loading branch information
shashank40 committed Jun 19, 2024
1 parent 888524c commit d4a1b34
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 10 deletions.
7 changes: 7 additions & 0 deletions build_scripts/get_version.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
"""Get the version of the package."""

import importlib.metadata
import requests
import json

APP_VERSION_URL = "https://api.github.com/repos/OpenAdaptAI/OpenAdapt/releases?per_page=10&page=1"

def get_version() -> str:
"""Get the version of the package."""
return importlib.metadata.version("openadapt")

def get_latest_version() -> str:
response = requests.get(APP_VERSION_URL, stream=True)
data = json.loads(response.text)
return data[0]['tag_name'].replace('v', '')

if __name__ == "__main__":
print(get_version())
78 changes: 78 additions & 0 deletions openadapt/app/tray.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
import multiprocessing
import os
import sys
import requests
from urllib.parse import urlparse
import threading
from tqdm import tqdm

from loguru import logger
from pyqttoast import Toast, ToastButtonAlignment, ToastIcon, ToastPosition, ToastPreset
Expand Down Expand Up @@ -45,11 +49,17 @@
from openadapt.strategies.base import BaseReplayStrategy
from openadapt.utils import get_posthog_instance
from openadapt.visualize import main as visualize
from build_scripts.get_version import get_version, get_latest_version
from packaging.version import Version

# ensure all strategies are registered
import openadapt.strategies # noqa: F401

ICON_PATH = os.path.join(FPATH, "assets", "logo.png")
APP_DOWNLOAD_BASE_URL = "https://github.com/OpenAdaptAI/OpenAdapt/releases/download"
CANCEL_APP_DOWNLOAD = False
CURRENT_VERSION = get_version()
LATEST_VERSION = get_latest_version()


class TrackedQAction(QAction):
Expand Down Expand Up @@ -137,8 +147,14 @@ def __init__(self) -> None:
self.dashboard_action.triggered.connect(self.launch_dashboard)
self.menu.addAction(self.dashboard_action)

self.download_button_text = f"Download Latest Version v{LATEST_VERSION}" if Version(CURRENT_VERSION) < Version(LATEST_VERSION) else "No updates available"
self.download_update_action = TrackedQAction(self.download_button_text)
self.download_update_action.triggered.connect(self.download_latest_app_version)
self.menu.addAction(self.download_update_action)

self.quit = TrackedQAction("Quit")


def _quit() -> None:
"""Quit the application."""
if self.dashboard_thread is not None:
Expand Down Expand Up @@ -168,6 +184,68 @@ def _quit() -> None:
# for storing toasts that should be manually removed
self.sticky_toasts = {}

def stop_download(self) -> None:
global CANCEL_APP_DOWNLOAD
self.show_toast("Stopping download...", duration=4000)
CANCEL_APP_DOWNLOAD = True

def download_latest_version(self, base_url: str, latest_version: str) -> None:
global CANCEL_APP_DOWNLOAD

DOWNLOAD_URL = ""
FILE_NAME = ""

if sys.platform == "darwin":
FILE_NAME = f"OpenAdapt-v{latest_version}.app.zip"
DOWNLOAD_URL = base_url + f"/v{latest_version}/{FILE_NAME}"
else:
FILE_NAME = f"OpenAdapt-v{latest_version}.zip"
DOWNLOAD_URL = base_url + f"/v{latest_version}/{FILE_NAME}"

parsed_url = urlparse(DOWNLOAD_URL)
filename = os.path.basename(parsed_url.path)
downloads_path = os.path.join(os.path.expanduser("~"), "Downloads")
local_filename = os.path.join(downloads_path, filename)

response = requests.get(DOWNLOAD_URL, stream=True)
total_size = response.headers.get('content-length')
total_size = int(total_size) if total_size else None
block_size = 1024 # 1 Kilobyte
with open(local_filename, 'wb') as file, tqdm(
total=total_size, unit='B', unit_scale=True, desc=filename
) as progress_bar:
for data in response.iter_content(block_size):
if CANCEL_APP_DOWNLOAD:
CANCEL_APP_DOWNLOAD = False
break
file.write(data)
progress_bar.update(len(data))


def check_and_download_latest_version(self) -> None:
"""Check and Download latest version"""

if Version(CURRENT_VERSION) >= Version(LATEST_VERSION):
self.show_toast("You are already on the latest version.")
return

self.show_toast("Downloading the latest version...", duration=4000)
download_thread = threading.Thread(target=self.download_latest_version, args=(APP_DOWNLOAD_BASE_URL, LATEST_VERSION))
download_thread.start()

self.show_toast("After download, use the latest app version", duration=10000)


def download_latest_app_version(self) -> None:
global CANCEL_APP_DOWNLOAD

if self.download_update_action.text() == "Stop Download":
self.stop_download()
self.download_update_action.setText(self.download_button_text)
elif not CANCEL_APP_DOWNLOAD:
self.download_update_action.setText("Stop Download")
self.check_and_download_latest_version()

def handle_recording_signal(
self,
notifier: QSocketNotifier,
Expand Down
19 changes: 9 additions & 10 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ posthog = "^3.5.0"

wheel = "^0.43.0"
cython = "^3.0.10"
packaging = "^24.1"
urllib3 = "^2.2.2"
[tool.pytest.ini_options]
filterwarnings = [
# suppress warnings starting from "setuptools>=67.3"
Expand Down

0 comments on commit d4a1b34

Please sign in to comment.