fix to app not updating

This commit is contained in:
2026-08-31 23:37:12 -07:00
parent 2fe6f42c48
commit 8ef352add3
4 changed files with 201 additions and 167 deletions
+52 -32
View File
@@ -20,21 +20,24 @@ from pathlib import Path
from datetime import datetime
# External library imports
from src.shared.shareddata import APP_NAME, PLATFORM_NAME
from src.shared.shareddata import APP_NAME, PLATFORM_NAME, get_app_dir
if PLATFORM_NAME == 'darwin':
_log_path = os.path.join(os.path.dirname(sys.executable), f"../../../{APP_NAME}_updater.log")
else:
_log_path = os.path.join(os.getcwd(), f"{APP_NAME}_updater.log")
_log_path = os.path.join(get_app_dir(), f"{APP_NAME}_updater.log")
LOG_FILE = _log_path
def log(msg: str) -> None:
with open(LOG_FILE, "a", encoding="utf-8") as f:
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
f.write(f"{timestamp} - {msg}\n")
try:
with open(LOG_FILE, "a", encoding="utf-8") as f:
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
f.write(f"{timestamp} - {msg}\n")
except Exception:
pass
def kill_all_processes_by_executable(exe_path: Union[str, Path]) -> bool:
@@ -45,22 +48,28 @@ def kill_all_processes_by_executable(exe_path: Union[str, Path]) -> bool:
for proc in psutil.process_iter(['pid', 'exe']):
try:
proc_exe = proc.info.get('exe')
if proc_exe and os.path.samefile(os.path.realpath(proc_exe), exe_path):
log(f"Terminating process: PID {proc.pid}")
_terminate_process(proc)
terminated_any = True
if proc_exe and os.path.exists(proc_exe) and os.path.exists(exe_path):
if os.path.samefile(os.path.realpath(proc_exe), exe_path):
log(f"Terminating process: PID {proc.pid}")
_terminate_process(proc)
terminated_any = True
except (psutil.NoSuchProcess, psutil.AccessDenied, FileNotFoundError) as e:
continue
except Exception as e:
log(f"Error terminating process (Windows): {e}")
elif PLATFORM_NAME == 'linux':
for proc in psutil.process_iter(['pid', 'cmdline']):
try:
cmdline = proc.info.get('cmdline', [])
if cmdline:
if cmdline and os.path.exists(cmdline[0]) and os.path.exists(exe_path):
proc_cmd = os.path.realpath(cmdline[0])
if os.path.samefile(proc_cmd, exe_path):
log(f"Terminating process: PID {proc.pid}")
_terminate_process(proc)
terminated_any = True
except (psutil.NoSuchProcess, psutil.AccessDenied, FileNotFoundError) as e:
continue
except Exception as e:
log(f"Error terminating process (Linux): {e}")
@@ -82,6 +91,9 @@ def _terminate_process(proc: psutil.Process) -> None:
def wait_for_unlock(path: Union[str, Path], timeout: Union[int, float] = 100) -> None:
if not os.path.exists(path):
return
start_time = time.time()
while time.time() - start_time < timeout:
try:
@@ -95,7 +107,7 @@ def wait_for_unlock(path: Union[str, Path], timeout: Union[int, float] = 100) ->
log(f"Still locked: {path} - {e}")
time.sleep(1)
log(f"Failed to delete after wait: {path}")
def delete_path(path: Union[str, Path]) -> None:
if os.path.exists(path):
@@ -130,8 +142,8 @@ def copy_update_files(src_folder: Union[str, Path], dest_folder: Union[str, Path
def copy_update_files_darwin(src_folder: Union[str, Path], dest_folder: Union[str, Path], updater_name: str) -> None:
updater_name = updater_name + ".app"
if not updater_name.endswith(".app"):
updater_name = updater_name + ".app"
for item in os.listdir(src_folder):
if item.lower() == updater_name.lower():
@@ -152,10 +164,7 @@ def copy_update_files_darwin(src_folder: Union[str, Path], dest_folder: Union[st
def remove_quarantine(app_path: Union[str, Path]) -> bool:
"""Removes the macOS quarantine extended attribute from an application bundle using osascript.
Returns True on success, False on error or cancellation.
"""
"""Removes the macOS quarantine extended attribute from an application bundle using osascript."""
clean_path: str = str(app_path)
escaped_path: str = shlex.quote(clean_path)
@@ -172,7 +181,7 @@ def remove_quarantine(app_path: Union[str, Path]) -> bool:
return False
def main():
def main() -> None:
main_exe: str = ""
app_dir: Path = Path()
bundle_dir: Path = Path()
@@ -189,17 +198,24 @@ def main():
main_exe = sys.argv[2]
main_exe_path = Path(main_exe).resolve()
app_dir = main_exe_path.parent
bundle_dir = main_exe_path.parents[2]
parent_bundle_dir = main_exe_path.parents[3]
app_dir = main_exe_path.parent
updater_name = os.path.basename(sys.argv[0])
if PLATFORM_NAME == 'darwin':
# Bundle hierarchy on macOS: App.app/Contents/MacOS/executable
if len(main_exe_path.parents) >= 4:
bundle_dir = main_exe_path.parents[2]
parent_bundle_dir = main_exe_path.parents[3]
else:
bundle_dir = app_dir
parent_bundle_dir = app_dir.parent
updater_name = os.path.basename(sys.executable if getattr(sys, 'frozen', False) else sys.argv[0])
log("Updater started.")
log(f"Update folder: {update_folder}")
log(f"Main EXE: {main_exe}")
log(f"Updater EXE: {updater_name}")
if PLATFORM_NAME == 'darwin':
if PLATFORM_NAME == 'darwin' and bundle_dir:
log(f"Main App Folder: {bundle_dir}")
# Kill all instances of main app
@@ -212,18 +228,22 @@ def main():
try:
if PLATFORM_NAME == 'windows':
proc_exe = proc.info.get('exe')
if proc_exe and os.path.samefile(os.path.realpath(proc_exe), os.path.realpath(main_exe)):
running = True
break
if proc_exe and os.path.exists(proc_exe) and os.path.exists(main_exe):
if os.path.samefile(os.path.realpath(proc_exe), os.path.realpath(main_exe)):
running = True
break
elif PLATFORM_NAME == 'linux':
cmdline = proc.info.get('cmdline', [])
if cmdline:
if cmdline and os.path.exists(cmdline[0]) and os.path.exists(main_exe):
proc_cmd = os.path.realpath(cmdline[0])
if os.path.samefile(proc_cmd, os.path.realpath(main_exe)):
running = True
break
except (psutil.NoSuchProcess, psutil.AccessDenied, FileNotFoundError):
continue
except Exception as e:
log(f"Polling error: {e}")
if not running:
break
time.sleep(0.5)
@@ -231,11 +251,11 @@ def main():
log("Warning: main executable still running after wait timeout.")
# Delete old version files
if PLATFORM_NAME == 'darwin':
if PLATFORM_NAME == 'darwin' and bundle_dir and parent_bundle_dir:
log(f'Attempting to delete {bundle_dir}')
delete_path(str(bundle_dir))
update_folder = os.path.join(sys.argv[1], f"{APP_NAME}-darwin")
copy_update_files_darwin(update_folder, str(parent_bundle_dir), updater_name)
extracted_update_folder = os.path.join(update_folder, f"{APP_NAME}-darwin")
copy_update_files_darwin(extracted_update_folder, str(parent_bundle_dir), updater_name)
else:
delete_path(main_exe)
@@ -252,8 +272,8 @@ def main():
if PLATFORM_NAME == 'linux':
os.chmod(main_exe, 0o755)
log("Added executable bit")
if PLATFORM_NAME == 'darwin':
if PLATFORM_NAME == 'darwin' and bundle_dir:
os.chmod(str(bundle_dir), 0o755)
log("Added executable bit")
remove_quarantine(str(bundle_dir))