From 018d598cde5109bad42a365b2ef30f3e5c9f221e Mon Sep 17 00:00:00 2001
From: Zehen-249 <1hasanmehendi123@gmail.com>
Date: Wed, 20 Aug 2025 11:00:25 +0530
Subject: [PATCH 01/11] [Refactor] update_version_check.py
---
src/osdag/update_version_check.py | 88 +++++++++++++++----------------
1 file changed, 44 insertions(+), 44 deletions(-)
diff --git a/src/osdag/update_version_check.py b/src/osdag/update_version_check.py
index 312cff3a7..8cab2fb53 100644
--- a/src/osdag/update_version_check.py
+++ b/src/osdag/update_version_check.py
@@ -1,55 +1,55 @@
######################### UpDateNotifi ################
+
import urllib.request
-import requests
import re
-from PyQt5.QtWidgets import QMessageBox,QMainWindow
-import sys
+from pathlib import Path
+
+version_file = Path(__file__).parent / "_version.py"
+ns = {}
+exec(version_file.read_text(), ns)
+curr_version = ns["__version__"]
class Update():
+ URL = "https://osdag.fossee.in/resources/downloads"
+ PATTERN = re.compile(r'Install Osdag \((v[0-9a-zA-Z_]+)\)')
+
def __init__(self):
super().__init__()
- self.old_version=self.get_current_version()
- # msg = self.notifi()
+ self.old_version = curr_version
- def notifi(self):
+ def fetch_latest_version(self) -> str:
+ """Fetch the latest version string from Osdag downloads page."""
try:
- url = "https://raw.githubusercontent.com/osdag-admin/Osdag/master/README.md"
- file = urllib.request.urlopen(url)
- version = 'not found'
- for line in file:
- decoded_line = line.decode("utf-8")
- match = re.search(r'Download the latest release version (\S+)', decoded_line)
- if match:
- version = match.group(1)
- version = version.split("<")[0]
- break
- # decoded_line = line.decode("utf-8")
- # new_version = decoded_line.split("=")[1]
- if version != self.old_version:
- msg = 'Current version: '+ self.old_version+'
'+'Latest version '+ str(version)+'
'+\
- 'Update will be available here '
- else:
- msg = 'Already up to date'
- return msg
- except:
- return "No internet connection"
-
- def get_current_version(self):
- version_file = "_version.py"
- rel_path = str(sys.path[0])
- rel_path = rel_path.replace("\\", "/")
- VERSIONFILE = rel_path +'/'+ version_file
+ with urllib.request.urlopen(self.URL) as response:
+ for line in response:
+ decoded_line = line.decode("utf-8")
+ match = self.PATTERN.search(decoded_line)
+ if match:
+ return match.group(1)
+ return "not found"
+ except Exception as e:
+ raise ConnectionError(f"Error fetching latest version: {e}")
+ def notifi(self) -> str:
+ """Compare current version with latest version and return update message."""
try:
- verstrline = open(VERSIONFILE, "rt").read()
- except EnvironmentError:
- pass # Okay, there is no version file.
- else:
- VSRE = r"^__version__ = ['\"]([^'\"]*)['\"]"
- mo = re.search(VSRE, verstrline, re.M)
- if mo:
- verstr = mo.group(1)
- return verstr
- else:
- print("unable to find version in %s" % (VERSIONFILE,))
- raise RuntimeError("if %s.py exists, it is required to be well-formed" % (VERSIONFILE,))
+ latest_version = self.fetch_latest_version().lstrip("v").replace("_", ".")
+ print(f"Latest version found: {latest_version}")
+
+ if latest_version == "not found":
+ return "Could not determine latest version."
+
+ if latest_version != self.old_version:
+ return (
+ f"Current version: {self.old_version}
"
+ f"Latest version: {latest_version}
"
+ f'Update will be available '
+ f'here'
+ )
+
+ return "Already up to date"
+
+ except Exception as e:
+ return str(e)
+
+
From 935e3c925d0b767122ad911717cd6ba214f11950 Mon Sep 17 00:00:00 2001
From: Zehen-249 <1hasanmehendi123@gmail.com>
Date: Wed, 20 Aug 2025 13:35:45 +0530
Subject: [PATCH 02/11] Add update_now and update_later buttons
---
src/osdag/osdagMainPage.py | 23 ++++++++++++++++++++++-
src/osdag/update_version_check.py | 4 ----
2 files changed, 22 insertions(+), 5 deletions(-)
diff --git a/src/osdag/osdagMainPage.py b/src/osdag/osdagMainPage.py
index 0cfc08b51..845d81da9 100644
--- a/src/osdag/osdagMainPage.py
+++ b/src/osdag/osdagMainPage.py
@@ -511,7 +511,28 @@ def selection_change(self):
elif loc == "Check for Update":
update_class = Update()
msg = update_class.notifi()
- QMessageBox.information(self, 'Info',msg)
+ # QMessageBox.information(self, 'Info',msg)
+
+ box = QMessageBox(self)
+ box.setIcon(QMessageBox.Information)
+ box.setWindowTitle("Check for Updates")
+ box.setText(msg)
+
+ if msg != "Already up to date":
+ # Add buttons
+ update_now_btn = box.addButton("Update Now", QMessageBox.AcceptRole)
+ later_btn = box.addButton("Update Later", QMessageBox.RejectRole)
+ else:
+ ok_btn = box.addButton("OK", QMessageBox.AcceptRole)
+
+ box.exec_()
+
+ if msg != "Already up to date":
+ if box.clickedButton() == update_now_btn:
+ pass
+ elif box.clickedButton() == later_btn:
+ pass
+
# elif loc == "FAQ":
# pass
diff --git a/src/osdag/update_version_check.py b/src/osdag/update_version_check.py
index 8cab2fb53..ea31d1489 100644
--- a/src/osdag/update_version_check.py
+++ b/src/osdag/update_version_check.py
@@ -34,8 +34,6 @@ def notifi(self) -> str:
"""Compare current version with latest version and return update message."""
try:
latest_version = self.fetch_latest_version().lstrip("v").replace("_", ".")
- print(f"Latest version found: {latest_version}")
-
if latest_version == "not found":
return "Could not determine latest version."
@@ -43,8 +41,6 @@ def notifi(self) -> str:
return (
f"Current version: {self.old_version}
"
f"Latest version: {latest_version}
"
- f'Update will be available '
- f'here'
)
return "Already up to date"
From 2a9bb291a3f97a5b40308eb6b6571a7d9593857b Mon Sep 17 00:00:00 2001
From: Zehen-249 <1hasanmehendi123@gmail.com>
Date: Wed, 20 Aug 2025 21:35:17 +0530
Subject: [PATCH 03/11] fix minor bugs and inconsistency
---
src/osdag/_version.py | 1 +
src/osdag/osdagMainPage.py | 26 ++++++++++++------
src/osdag/update_version_check.py | 45 ++++++++++++++++---------------
3 files changed, 43 insertions(+), 29 deletions(-)
diff --git a/src/osdag/_version.py b/src/osdag/_version.py
index ab6e815b2..7ae7b3376 100644
--- a/src/osdag/_version.py
+++ b/src/osdag/_version.py
@@ -1 +1,2 @@
__version__ = "2025.01.a.2"
+__installation_type__ = "conda"
\ No newline at end of file
diff --git a/src/osdag/osdagMainPage.py b/src/osdag/osdagMainPage.py
index 845d81da9..bf6125219 100644
--- a/src/osdag/osdagMainPage.py
+++ b/src/osdag/osdagMainPage.py
@@ -510,16 +510,19 @@ def selection_change(self):
self.ask_question()
elif loc == "Check for Update":
update_class = Update()
- msg = update_class.notifi()
+ try:
+ update_avl, msg = update_class.notifi()
+ except ConnectionError as e:
+ QMessageBox.critical(self, "Network Error", str(e))
+ return
# QMessageBox.information(self, 'Info',msg)
box = QMessageBox(self)
box.setIcon(QMessageBox.Information)
- box.setWindowTitle("Check for Updates")
+ box.setWindowTitle("Update Status")
box.setText(msg)
- if msg != "Already up to date":
- # Add buttons
+ if update_avl:
update_now_btn = box.addButton("Update Now", QMessageBox.AcceptRole)
later_btn = box.addButton("Update Later", QMessageBox.RejectRole)
else:
@@ -527,11 +530,18 @@ def selection_change(self):
box.exec_()
- if msg != "Already up to date":
+ if update_avl:
if box.clickedButton() == update_now_btn:
- pass
- elif box.clickedButton() == later_btn:
- pass
+ confirm_update = QMessageBox(self)
+ confirm_update.setIcon(QMessageBox.Information)
+ confirm_update.setWindowTitle("Confirm Update")
+ confirm_update.setText("This may take some time....\nDo you want to continue?")
+ confirm_update.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
+ confirm_update.setDefaultButton(QMessageBox.No)
+
+ result = confirm_update.exec_()
+ if result == QMessageBox.Yes:
+ pass
# elif loc == "FAQ":
# pass
diff --git a/src/osdag/update_version_check.py b/src/osdag/update_version_check.py
index ea31d1489..89704f0e9 100644
--- a/src/osdag/update_version_check.py
+++ b/src/osdag/update_version_check.py
@@ -3,15 +3,16 @@
import urllib.request
import re
from pathlib import Path
+from packaging.version import Version, InvalidVersion
version_file = Path(__file__).parent / "_version.py"
-ns = {}
-exec(version_file.read_text(), ns)
-curr_version = ns["__version__"]
+version_var = {}
+exec(version_file.read_text(), version_var)
+curr_version = version_var["__version__"]
class Update():
URL = "https://osdag.fossee.in/resources/downloads"
- PATTERN = re.compile(r'Install Osdag \((v[0-9a-zA-Z_]+)\)')
+ PATTERN = re.compile(r'Install\s+Osdag\s*\(\s*v([\w._-]+)\s*\)', re.IGNORECASE)
def __init__(self):
super().__init__()
@@ -26,26 +27,28 @@ def fetch_latest_version(self) -> str:
match = self.PATTERN.search(decoded_line)
if match:
return match.group(1)
- return "not found"
- except Exception as e:
- raise ConnectionError(f"Error fetching latest version: {e}")
+ return None
+ except urllib.error.URLError as e:
+ raise ConnectionError(f"Network error: {e.reason}")
+ except urllib.error.HTTPError as e:
+ raise ConnectionError(f"HTTP error {e.code}: {e.reason}")
def notifi(self) -> str:
"""Compare current version with latest version and return update message."""
try:
- latest_version = self.fetch_latest_version().lstrip("v").replace("_", ".")
- if latest_version == "not found":
- return "Could not determine latest version."
-
- if latest_version != self.old_version:
- return (
- f"Current version: {self.old_version}
"
- f"Latest version: {latest_version}
"
+ latest_version = self.fetch_latest_version()
+ if latest_version is None:
+ return False, "Could not determine latest version."
+
+ latest_version = latest_version.lstrip("v").replace("_", ".")
+ if Version(latest_version) > Version(self.old_version):
+ return True, (
+ f"Current version: {self.old_version}\n"
+ f"Latest version: {latest_version}\n"
)
-
- return "Already up to date"
-
- except Exception as e:
- return str(e)
-
+ else:
+ return False, "Already up to date"
+
+ except InvalidVersion:
+ return False, "Could not parse version string."
From b4ff568a88ecf383932a39b47c2da6e9a46814e4 Mon Sep 17 00:00:00 2001
From: Zehen-249 <1hasanmehendi123@gmail.com>
Date: Wed, 20 Aug 2025 22:36:43 +0530
Subject: [PATCH 04/11] add update_to_latest method to show dummy update
---
src/osdag/_version.py | 2 +-
src/osdag/osdagMainPage.py | 2 +-
src/osdag/update_version_check.py | 32 ++++++++++++++++++++++++++++++-
3 files changed, 33 insertions(+), 3 deletions(-)
diff --git a/src/osdag/_version.py b/src/osdag/_version.py
index 7ae7b3376..5e987e66b 100644
--- a/src/osdag/_version.py
+++ b/src/osdag/_version.py
@@ -1,2 +1,2 @@
-__version__ = "2025.01.a.2"
+__version__ = "2025.01.a.1"
__installation_type__ = "conda"
\ No newline at end of file
diff --git a/src/osdag/osdagMainPage.py b/src/osdag/osdagMainPage.py
index bf6125219..9568a7014 100644
--- a/src/osdag/osdagMainPage.py
+++ b/src/osdag/osdagMainPage.py
@@ -541,7 +541,7 @@ def selection_change(self):
result = confirm_update.exec_()
if result == QMessageBox.Yes:
- pass
+ print(update_class.update_to_latest())
# elif loc == "FAQ":
# pass
diff --git a/src/osdag/update_version_check.py b/src/osdag/update_version_check.py
index 89704f0e9..968eb3472 100644
--- a/src/osdag/update_version_check.py
+++ b/src/osdag/update_version_check.py
@@ -4,19 +4,24 @@
import re
from pathlib import Path
from packaging.version import Version, InvalidVersion
+from PyQt5.QtCore import QObject, QProcess, pyqtSignal
+import subprocess
+
version_file = Path(__file__).parent / "_version.py"
version_var = {}
exec(version_file.read_text(), version_var)
curr_version = version_var["__version__"]
-class Update():
+class Update(QObject):
+
URL = "https://osdag.fossee.in/resources/downloads"
PATTERN = re.compile(r'Install\s+Osdag\s*\(\s*v([\w._-]+)\s*\)', re.IGNORECASE)
def __init__(self):
super().__init__()
self.old_version = curr_version
+ self.process = None
def fetch_latest_version(self) -> str:
"""Fetch the latest version string from Osdag downloads page."""
@@ -51,4 +56,29 @@ def notifi(self) -> str:
except InvalidVersion:
return False, "Could not parse version string."
+
+ def update_to_latest(self):
+ """Run conda update in background using QProcess."""
+ try:
+ latest_version = self.fetch_latest_version()
+ if latest_version:
+ latest_version = latest_version.lstrip("v").replace("_", ".")
+ except Exception as e:
+ return
+ try:
+ # safer conda install
+ # cmd = ["conda", "install", "-y", f"osdag=={latest_version}"]
+ cmd = ["cmd", "/c", f"echo Updating to version {latest_version} && timeout /t 5"]
+
+ result = subprocess.run(cmd, capture_output=False, text=True)
+ if result.returncode == 0:
+ return (True, "Update successful! Please restart Osdag.")
+ else:
+ return (False, f"Update failed.\nError: {result.stderr}\n"
+ "Please retry or run:\nconda install --force-reinstall osdag::osdag")
+
+
+ except Exception as e:
+ return (False, f"Update failed: {e}")
+
\ No newline at end of file
From 8a01011c1cf736f45e3dc7d07950d2d28d179b07 Mon Sep 17 00:00:00 2001
From: Zehen-249 <1hasanmehendi123@gmail.com>
Date: Wed, 20 Aug 2025 22:39:58 +0530
Subject: [PATCH 05/11] seperate pixi and conda based installation updates
---
src/osdag/update_version_check.py | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/osdag/update_version_check.py b/src/osdag/update_version_check.py
index 968eb3472..9105a68a1 100644
--- a/src/osdag/update_version_check.py
+++ b/src/osdag/update_version_check.py
@@ -12,7 +12,7 @@
version_var = {}
exec(version_file.read_text(), version_var)
curr_version = version_var["__version__"]
-
+install_type = version_var["__installation_type__"]
class Update(QObject):
URL = "https://osdag.fossee.in/resources/downloads"
@@ -68,7 +68,10 @@ def update_to_latest(self):
try:
# safer conda install
# cmd = ["conda", "install", "-y", f"osdag=={latest_version}"]
- cmd = ["cmd", "/c", f"echo Updating to version {latest_version} && timeout /t 5"]
+ if install_type == "conda":
+ cmd = ["cmd", "/c", f"echo Updating to version {latest_version} with conda && timeout /t 5"]
+ elif install_type == "pixi":
+ cmd = ["cmd", "/c", f"echo Updating to version {latest_version} with pixi && timeout /t 5"]
result = subprocess.run(cmd, capture_output=False, text=True)
if result.returncode == 0:
From 01d4950c2f541ea6d609350f52fdc744717a5600 Mon Sep 17 00:00:00 2001
From: Zehen-249 <1hasanmehendi123@gmail.com>
Date: Wed, 20 Aug 2025 22:52:18 +0530
Subject: [PATCH 06/11] add synchronised update feature for conda(GUI block
until update completes)
---
src/osdag/osdagMainPage.py | 6 +++++-
src/osdag/update_version_check.py | 6 +++---
2 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/src/osdag/osdagMainPage.py b/src/osdag/osdagMainPage.py
index 9568a7014..a457f905e 100644
--- a/src/osdag/osdagMainPage.py
+++ b/src/osdag/osdagMainPage.py
@@ -541,7 +541,11 @@ def selection_change(self):
result = confirm_update.exec_()
if result == QMessageBox.Yes:
- print(update_class.update_to_latest())
+ update_status, msg = update_class.update_to_latest()
+ if update_status:
+ QMessageBox.information(self, "Update", msg)
+ else:
+ QMessageBox.warning(self, "Update Failed", msg)
# elif loc == "FAQ":
# pass
diff --git a/src/osdag/update_version_check.py b/src/osdag/update_version_check.py
index 9105a68a1..c4a6e6d29 100644
--- a/src/osdag/update_version_check.py
+++ b/src/osdag/update_version_check.py
@@ -66,12 +66,12 @@ def update_to_latest(self):
except Exception as e:
return
try:
- # safer conda install
# cmd = ["conda", "install", "-y", f"osdag=={latest_version}"]
if install_type == "conda":
- cmd = ["cmd", "/c", f"echo Updating to version {latest_version} with conda && timeout /t 5"]
+ cmd = ["conda", "update", "-y", f"osdag"]
+ # cmd = ["cmd", "/c", f"echo Updating to version {latest_version} with conda && timeout /t 5"]
elif install_type == "pixi":
- cmd = ["cmd", "/c", f"echo Updating to version {latest_version} with pixi && timeout /t 5"]
+ cmd = ["pixi", "update", "-y", f"osdag"]
result = subprocess.run(cmd, capture_output=False, text=True)
if result.returncode == 0:
From 4467ef51161bff5a0e53cb812346d37ecfacbd91 Mon Sep 17 00:00:00 2001
From: Zehen-249 <1hasanmehendi123@gmail.com>
Date: Wed, 20 Aug 2025 23:11:04 +0530
Subject: [PATCH 07/11] Add conda.exe and pixi.exe executable paths
---
src/osdag/update_version_check.py | 22 +++++++++++++++++++---
1 file changed, 19 insertions(+), 3 deletions(-)
diff --git a/src/osdag/update_version_check.py b/src/osdag/update_version_check.py
index c4a6e6d29..9309fb9b9 100644
--- a/src/osdag/update_version_check.py
+++ b/src/osdag/update_version_check.py
@@ -6,6 +6,7 @@
from packaging.version import Version, InvalidVersion
from PyQt5.QtCore import QObject, QProcess, pyqtSignal
import subprocess
+import sys, os
version_file = Path(__file__).parent / "_version.py"
@@ -67,11 +68,26 @@ def update_to_latest(self):
return
try:
# cmd = ["conda", "install", "-y", f"osdag=={latest_version}"]
+
+ env_path = sys.prefix
+ env_path = Path(env_path)
+ base_conda_path = env_path.parents[1]
+ if sys.platform.startswith("win"):
+ conda_path = base_conda_path / "Scripts" / "conda.exe"
+ pixi_path = env_path / "Scripts" / "pixi.exe"
+ print(conda_path, pixi_path)
+ else:
+ conda_path = base_conda_path / "bin/conda"
+ pixi_path = env_path / "bin/pixi"
if install_type == "conda":
- cmd = ["conda", "update", "-y", f"osdag"]
- # cmd = ["cmd", "/c", f"echo Updating to version {latest_version} with conda && timeout /t 5"]
+ if not conda_path.exists():
+ return False, f"conda.exe not found in {conda_path}"
+ # cmd = [str(conda_path), "update", "-y", f"osdag"]
+ cmd = ["cmd", "/c", f"echo Updating to version {latest_version} with conda && timeout /t 5"]
elif install_type == "pixi":
- cmd = ["pixi", "update", "-y", f"osdag"]
+ if not pixi_path.exists():
+ return False, f"pixi.exe not found in {pixi_path}"
+ cmd = [str(pixi_path), "update", "-y", f"osdag"]
result = subprocess.run(cmd, capture_output=False, text=True)
if result.returncode == 0:
From 0a3841fef3a1325bf4f93ff403d0f304802e0760 Mon Sep 17 00:00:00 2001
From: Zehen-249 <1hasanmehendi123@gmail.com>
Date: Thu, 21 Aug 2025 10:08:12 +0530
Subject: [PATCH 08/11] Add asyn update feature using QProcess
---
src/osdag/osdagMainPage.py | 26 ++++++++----
src/osdag/update_version_check.py | 68 ++++++++++++++++++++++++-------
2 files changed, 71 insertions(+), 23 deletions(-)
diff --git a/src/osdag/osdagMainPage.py b/src/osdag/osdagMainPage.py
index a457f905e..af811af53 100644
--- a/src/osdag/osdagMainPage.py
+++ b/src/osdag/osdagMainPage.py
@@ -509,9 +509,9 @@ def selection_change(self):
elif loc == "Ask Us a Question":
self.ask_question()
elif loc == "Check for Update":
- update_class = Update()
+ self.updater = Update()
try:
- update_avl, msg = update_class.notifi()
+ update_avl, msg = self.updater.notifi()
except ConnectionError as e:
QMessageBox.critical(self, "Network Error", str(e))
return
@@ -530,8 +530,7 @@ def selection_change(self):
box.exec_()
- if update_avl:
- if box.clickedButton() == update_now_btn:
+ if update_avl and box.clickedButton() == update_now_btn:
confirm_update = QMessageBox(self)
confirm_update.setIcon(QMessageBox.Information)
confirm_update.setWindowTitle("Confirm Update")
@@ -541,15 +540,24 @@ def selection_change(self):
result = confirm_update.exec_()
if result == QMessageBox.Yes:
- update_status, msg = update_class.update_to_latest()
- if update_status:
- QMessageBox.information(self, "Update", msg)
- else:
- QMessageBox.warning(self, "Update Failed", msg)
+
+ self.updater.output_signal.connect(lambda text: print(text, end=""))
+ self.updater.finished_signal.connect(self.handle_update_finished)
+ self.updater.update_to_latest()
+ # if update_status:
+ # QMessageBox.information(self, "Update", msg)
+ # else:
+ # QMessageBox.warning(self, "Update Failed", msg)
+
# elif loc == "FAQ":
# pass
+ def handle_update_finished(self,success, msg):
+ if success:
+ QMessageBox.information(self, "Update", msg)
+ else:
+ QMessageBox.warning(self, "Update Failed", msg)
def select_workspace_folder(self):
# This function prompts the user to select the workspace folder and returns the name of the workspace folder
diff --git a/src/osdag/update_version_check.py b/src/osdag/update_version_check.py
index 9309fb9b9..2494f7e08 100644
--- a/src/osdag/update_version_check.py
+++ b/src/osdag/update_version_check.py
@@ -15,6 +15,8 @@
curr_version = version_var["__version__"]
install_type = version_var["__installation_type__"]
class Update(QObject):
+ output_signal = pyqtSignal(str)
+ finished_signal = pyqtSignal(bool, str)
URL = "https://osdag.fossee.in/resources/downloads"
PATTERN = re.compile(r'Install\s+Osdag\s*\(\s*v([\w._-]+)\s*\)', re.IGNORECASE)
@@ -22,7 +24,7 @@ class Update(QObject):
def __init__(self):
super().__init__()
self.old_version = curr_version
- self.process = None
+ self.process = QProcess(self)
def fetch_latest_version(self) -> str:
"""Fetch the latest version string from Osdag downloads page."""
@@ -81,23 +83,61 @@ def update_to_latest(self):
pixi_path = env_path / "bin/pixi"
if install_type == "conda":
if not conda_path.exists():
- return False, f"conda.exe not found in {conda_path}"
- # cmd = [str(conda_path), "update", "-y", f"osdag"]
- cmd = ["cmd", "/c", f"echo Updating to version {latest_version} with conda && timeout /t 5"]
+ self.finished_signal.emit(False, f"conda not found at {conda_path}")
+ return
+ cmd = [str(conda_path), "update", "-y", "osdag"]
+ # cmd = ["cmd", "/c", f"echo Updating to version {latest_version} with conda && timeout /t 5"]
elif install_type == "pixi":
if not pixi_path.exists():
- return False, f"pixi.exe not found in {pixi_path}"
- cmd = [str(pixi_path), "update", "-y", f"osdag"]
+ self.finished_signal.emit(False, f"pixi.exe not found in {pixi_path}")
+ return
+ cmd = [str(pixi_path), "update", "-y", "osdag"]
- result = subprocess.run(cmd, capture_output=False, text=True)
- if result.returncode == 0:
- return (True, "Update successful! Please restart Osdag.")
- else:
- return (False, f"Update failed.\nError: {result.stderr}\n"
- "Please retry or run:\nconda install --force-reinstall osdag::osdag")
+ # Create QProcess
+ self.process.setProgram(cmd[0])
+ self.process.setArguments(cmd[1:])
+
+ # Connect signals for output
+ self.process.readyReadStandardOutput.connect(self.handle_stdout)
+ self.process.readyReadStandardError.connect(self.handle_stderr)
+ self.process.finished.connect(self.handle_finished)
+
+ # Start the process
+ self.process.start()
+
+ # result = subprocess.run(cmd, capture_output=False, text=True)
+ # if result.returncode == 0:
+ # self.finished_signal.emit(True, "Update successful! Please restart Osdag.")
+ # else:
+ # self.finished_signal.emit(False, f"Update failed.\nError: {result.stderr}\n"
+ # "Please retry or run:\nconda install --force-reinstall osdag::osdag")
except Exception as e:
- return (False, f"Update failed: {e}")
+ self.finished_signal.emit(False, f"Update failed: {e}")
+ return
+
+
+ def handle_stdout(self):
+ """Read stdout and print it, also emit signal for GUI."""
+ if self.process:
+ output = self.process.readAllStandardOutput().data().decode()
+ print(output, end="")
+ self.output_signal.emit(output)
+
+ def handle_stderr(self):
+ """Read stderr and print it."""
+ if self.process:
+ error = self.process.readAllStandardError().data().decode()
+ print(error, end="")
+ self.output_signal.emit(error)
+
+ def handle_finished(self, exit_code, exit_status):
+ """Handle when the process finishes."""
+ if exit_code == 0:
+ self.finished_signal.emit(True, "Update successful! Please restart Osdag.")
+ else:
+ self.finished_signal.emit(False, f"Update failed with code {exit_code}")
+ self.process = None
-
\ No newline at end of file
+
\ No newline at end of file
From 04ea46c4478bc9f24a0486136c978b8018755a41 Mon Sep 17 00:00:00 2001
From: Zehen-249 <1hasanmehendi123@gmail.com>
Date: Thu, 21 Aug 2025 10:36:26 +0530
Subject: [PATCH 09/11] Add dialog box to show update status
---
src/osdag/osdagMainPage.py | 21 ++++++++++++++++++---
src/osdag/update_version_check.py | 19 +++++++++++++++----
2 files changed, 33 insertions(+), 7 deletions(-)
diff --git a/src/osdag/osdagMainPage.py b/src/osdag/osdagMainPage.py
index af811af53..da6a4475c 100644
--- a/src/osdag/osdagMainPage.py
+++ b/src/osdag/osdagMainPage.py
@@ -88,7 +88,7 @@
import time
from importlib.resources import files
import urllib.request
-from PyQt5.QtWidgets import QMessageBox,QApplication, QDialog, QMainWindow
+from PyQt5.QtWidgets import QMessageBox,QApplication, QDialog, QMainWindow, QTextEdit
from .update_version_check import Update
#from Thread import timer
from .get_DPI_scale import scale
@@ -540,8 +540,22 @@ def selection_change(self):
result = confirm_update.exec_()
if result == QMessageBox.Yes:
-
- self.updater.output_signal.connect(lambda text: print(text, end=""))
+ self.progress_dialog = QDialog(self)
+ self.progress_dialog.setWindowTitle("Updating Osdag")
+ layout = QVBoxLayout()
+
+ self.progress_label = QLabel("Updating, please wait...")
+ layout.addWidget(self.progress_label)
+
+ self.progress_text = QTextEdit()
+ self.progress_text.setReadOnly(True)
+ layout.addWidget(self.progress_text)
+
+ self.progress_dialog.setLayout(layout)
+ self.progress_dialog.setModal(True)
+ self.progress_dialog.show()
+
+ self.updater.output_signal.connect(lambda text: self.progress_text.append(text))
self.updater.finished_signal.connect(self.handle_update_finished)
self.updater.update_to_latest()
# if update_status:
@@ -554,6 +568,7 @@ def selection_change(self):
# pass
def handle_update_finished(self,success, msg):
+ self.progress_dialog.close()
if success:
QMessageBox.information(self, "Update", msg)
else:
diff --git a/src/osdag/update_version_check.py b/src/osdag/update_version_check.py
index 2494f7e08..46baeaa57 100644
--- a/src/osdag/update_version_check.py
+++ b/src/osdag/update_version_check.py
@@ -5,6 +5,7 @@
from pathlib import Path
from packaging.version import Version, InvalidVersion
from PyQt5.QtCore import QObject, QProcess, pyqtSignal
+from PyQt5.QtWidgets import QDialog, QTextEdit, QLabel
import subprocess
import sys, os
@@ -18,6 +19,7 @@ class Update(QObject):
output_signal = pyqtSignal(str)
finished_signal = pyqtSignal(bool, str)
+
URL = "https://osdag.fossee.in/resources/downloads"
PATTERN = re.compile(r'Install\s+Osdag\s*\(\s*v([\w._-]+)\s*\)', re.IGNORECASE)
@@ -121,16 +123,25 @@ def update_to_latest(self):
def handle_stdout(self):
"""Read stdout and print it, also emit signal for GUI."""
if self.process:
- output = self.process.readAllStandardOutput().data().decode()
- print(output, end="")
+ output = self.process.readAllStandardOutput().data().decode("utf-8")
self.output_signal.emit(output)
+ print(output, end="")
+ # self.progress_text.append(output)
+ # self.progress_text.verticalScrollBar().setValue(
+ # self.progress_text.verticalScrollBar().maximum()
+ # )
def handle_stderr(self):
"""Read stderr and print it."""
if self.process:
- error = self.process.readAllStandardError().data().decode()
- print(error, end="")
+ error = self.process.readAllStandardError().data().decode("utf-8")
self.output_signal.emit(error)
+ print(error, end="")
+ # self.output_signal.emit(error)
+ # self.progress_text.append(error)
+ # self.progress_text.verticalScrollBar().setValue(
+ # self.progress_text.verticalScrollBar().maximum()
+ # )
def handle_finished(self, exit_code, exit_status):
"""Handle when the process finishes."""
From 1fab443269f3384c58b20a01194a8b52ca6cadce Mon Sep 17 00:00:00 2001
From: Zehen-249 <1hasanmehendi123@gmail.com>
Date: Thu, 21 Aug 2025 10:44:17 +0530
Subject: [PATCH 10/11] Make update status box Non-modal
---
src/osdag/osdagMainPage.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/osdag/osdagMainPage.py b/src/osdag/osdagMainPage.py
index da6a4475c..b36491701 100644
--- a/src/osdag/osdagMainPage.py
+++ b/src/osdag/osdagMainPage.py
@@ -552,7 +552,8 @@ def selection_change(self):
layout.addWidget(self.progress_text)
self.progress_dialog.setLayout(layout)
- self.progress_dialog.setModal(True)
+ self.progress_dialog.setModal(False)
+ self.progress_dialog.setWindowFlags(self.progress_dialog.windowFlags() | Qt.WindowStaysOnTopHint)
self.progress_dialog.show()
self.updater.output_signal.connect(lambda text: self.progress_text.append(text))
From e1778c2416e09af2929cd195f2de5dd0788dcedf Mon Sep 17 00:00:00 2001
From: Zehen-249 <1hasanmehendi123@gmail.com>
Date: Wed, 10 Sep 2025 18:31:21 +0530
Subject: [PATCH 11/11] Use conda channel and pixi to fetch latest versions
---
src/osdag/osdagMainPage.py | 7 ++-
src/osdag/update_version_check.py | 89 ++++++++++++++++++-------------
2 files changed, 57 insertions(+), 39 deletions(-)
diff --git a/src/osdag/osdagMainPage.py b/src/osdag/osdagMainPage.py
index b36491701..d1be6d56f 100644
--- a/src/osdag/osdagMainPage.py
+++ b/src/osdag/osdagMainPage.py
@@ -549,10 +549,13 @@ def selection_change(self):
self.progress_text = QTextEdit()
self.progress_text.setReadOnly(True)
+ self.progress_text.verticalScrollBar().setValue(
+ self.progress_text.verticalScrollBar().maximum()
+ )
layout.addWidget(self.progress_text)
self.progress_dialog.setLayout(layout)
- self.progress_dialog.setModal(False)
+ self.progress_dialog.setModal(True)
self.progress_dialog.setWindowFlags(self.progress_dialog.windowFlags() | Qt.WindowStaysOnTopHint)
self.progress_dialog.show()
@@ -571,7 +574,7 @@ def selection_change(self):
def handle_update_finished(self,success, msg):
self.progress_dialog.close()
if success:
- QMessageBox.information(self, "Update", msg)
+ QMessageBox.information(self, "Update Completed", msg)
else:
QMessageBox.warning(self, "Update Failed", msg)
diff --git a/src/osdag/update_version_check.py b/src/osdag/update_version_check.py
index 46baeaa57..3f9184692 100644
--- a/src/osdag/update_version_check.py
+++ b/src/osdag/update_version_check.py
@@ -8,6 +8,7 @@
from PyQt5.QtWidgets import QDialog, QTextEdit, QLabel
import subprocess
import sys, os
+import json
version_file = Path(__file__).parent / "_version.py"
@@ -15,33 +16,60 @@
exec(version_file.read_text(), version_var)
curr_version = version_var["__version__"]
install_type = version_var["__installation_type__"]
+
+
+
class Update(QObject):
output_signal = pyqtSignal(str)
finished_signal = pyqtSignal(bool, str)
-
- URL = "https://osdag.fossee.in/resources/downloads"
- PATTERN = re.compile(r'Install\s+Osdag\s*\(\s*v([\w._-]+)\s*\)', re.IGNORECASE)
-
def __init__(self):
super().__init__()
self.old_version = curr_version
self.process = QProcess(self)
+
+ def _set_exec_paths(self):
+ env_path = sys.prefix
+ env_path = Path(env_path)
+ base_conda_path = env_path.parents[1]
+ if sys.platform.startswith("win"):
+ conda_path = base_conda_path / "Scripts" / "conda.exe"
+ pixi_path = env_path / "Scripts" / "pixi.exe"
+ else:
+ conda_path = base_conda_path / "bin/conda"
+ pixi_path = env_path / "bin/pixi"
+
+ self.conda_path = str(conda_path)
+ self.pixi_path = str(pixi_path)
def fetch_latest_version(self) -> str:
"""Fetch the latest version string from Osdag downloads page."""
- try:
- with urllib.request.urlopen(self.URL) as response:
- for line in response:
- decoded_line = line.decode("utf-8")
- match = self.PATTERN.search(decoded_line)
- if match:
- return match.group(1)
- return None
- except urllib.error.URLError as e:
- raise ConnectionError(f"Network error: {e.reason}")
- except urllib.error.HTTPError as e:
- raise ConnectionError(f"HTTP error {e.code}: {e.reason}")
+ self._set_exec_paths()
+ if install_type == "conda":
+ cmd = [self.conda_path, "search", "-c", "conda-forge", "osdag::osdag", "--info", "--json"]
+ try:
+ result = subprocess.run(cmd, capture_output=True, text=True, check=True)
+ data = json.loads(result.stdout)
+ except subprocess.CalledProcessError as e:
+ raise ConnectionError(f"Failed to fetch version info: {e.stderr}")
+ if data:
+ versions = data.get("osdag")
+ if versions:
+ return sorted(versions, key=lambda x:x["version"])[-1]["version"]
+ else: return None
+
+ elif install_type == "pixi":
+ cmd = [self.pixi_path, "search", "osdag", "--channel", "osdag"]
+ try:
+ result = subprocess.run(cmd, capture_output=True, text=True, check=True)
+ for line in result.stdout.splitlines():
+ if line.strip().startswith("Version"):
+ return line.split()[-1].strip()
+
+ else: return None
+
+ except subprocess.CalledProcessError as e:
+ raise ConnectionError(f"Failed to fetch version info: {e.stderr}")
def notifi(self) -> str:
"""Compare current version with latest version and return update message."""
@@ -73,27 +101,16 @@ def update_to_latest(self):
try:
# cmd = ["conda", "install", "-y", f"osdag=={latest_version}"]
- env_path = sys.prefix
- env_path = Path(env_path)
- base_conda_path = env_path.parents[1]
- if sys.platform.startswith("win"):
- conda_path = base_conda_path / "Scripts" / "conda.exe"
- pixi_path = env_path / "Scripts" / "pixi.exe"
- print(conda_path, pixi_path)
- else:
- conda_path = base_conda_path / "bin/conda"
- pixi_path = env_path / "bin/pixi"
if install_type == "conda":
- if not conda_path.exists():
- self.finished_signal.emit(False, f"conda not found at {conda_path}")
- return
- cmd = [str(conda_path), "update", "-y", "osdag"]
- # cmd = ["cmd", "/c", f"echo Updating to version {latest_version} with conda && timeout /t 5"]
+ if not Path(self.conda_path).exists():
+ self.finished_signal.emit(False, f"conda not found at {self.conda_path}")
+ return
+ cmd = [self.conda_path, "update", "-y", "osdag", "--channel", "osdag"]
elif install_type == "pixi":
- if not pixi_path.exists():
- self.finished_signal.emit(False, f"pixi.exe not found in {pixi_path}")
- return
- cmd = [str(pixi_path), "update", "-y", "osdag"]
+ if not Path(self.pixi_path).exists():
+ self.finished_signal.emit(False, f"pixi not found at {self.pixi_path}")
+ return
+ cmd = [self.pixi_path, "update", "-y", "osdag", "--channel", "osdag"]
# Create QProcess
self.process.setProgram(cmd[0])
@@ -150,5 +167,3 @@ def handle_finished(self, exit_code, exit_status):
else:
self.finished_signal.emit(False, f"Update failed with code {exit_code}")
self.process = None
-
-
\ No newline at end of file