fix to app not updating
This commit is contained in:
+52
-32
@@ -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))
|
||||
|
||||
Reference in New Issue
Block a user