diff --git a/core/updater.py b/core/updater.py index 703c7f3..3b075b6 100644 --- a/core/updater.py +++ b/core/updater.py @@ -262,75 +262,98 @@ class UpdateChecker: return self._apply_linux(binary_path, current_exe) def _apply_windows(self, new_exe: str, current_exe: str) -> bool: - """Windows update: PowerShell script waits for exit, copies, launches.""" + """Windows update: BAT script waits for exit, copies, launches.""" try: tmp_dir = tempfile.gettempdir() - ps_path = os.path.join(tmp_dir, "sm_update.ps1") - vbs_path = os.path.join(tmp_dir, "sm_update.vbs") + bat_path = os.path.join(tmp_dir, "sm_update.bat") + log_path = os.path.join(tmp_dir, "sm_update.log") pid = os.getpid() - mei_dir = getattr(sys, '_MEIPASS', '') - exe_dir = os.path.dirname(current_exe) - ps_content = f""" -$pid = {pid} -$src = '{new_exe}' -$dst = '{current_exe}' -$tempDir = '{tmp_dir}' + bat_content = f"""@echo off +chcp 65001 >nul 2>&1 +set "LOGFILE={log_path}" +set "SRC={new_exe}" +set "DST={current_exe}" +set "PID={pid}" +set "TMPDIR={tmp_dir}" -# Wait for old process to exit -while (Get-Process -Id $pid -ErrorAction SilentlyContinue) {{ - Start-Sleep -Seconds 1 -}} -Start-Sleep -Seconds 3 +echo [%date% %time%] Update script started >> "%LOGFILE%" +echo [%date% %time%] PID to wait for: %PID% >> "%LOGFILE%" +echo [%date% %time%] SRC: %SRC% >> "%LOGFILE%" +echo [%date% %time%] DST: %DST% >> "%LOGFILE%" -# Clean ALL stale _MEI directories (best-effort, skip locked) -try {{ - Get-ChildItem -Path $tempDir -Directory -Filter '_MEI*' -ErrorAction SilentlyContinue | ForEach-Object {{ - Remove-Item -Path $_.FullName -Recurse -Force -ErrorAction SilentlyContinue - }} -}} catch {{}} -Start-Sleep -Seconds 1 +:wait_loop +tasklist /FI "PID eq %PID%" 2>nul | find "%PID%" >nul +if %errorlevel%==0 ( + echo [%date% %time%] Waiting for PID %PID% to exit... >> "%LOGFILE%" + timeout /t 1 /nobreak >nul + goto wait_loop +) -# Copy with retry -$copied = $false -for ($i = 0; $i -lt 5; $i++) {{ - try {{ - Copy-Item -Path $src -Destination $dst -Force - $srcSize = (Get-Item $src).Length - $dstSize = (Get-Item $dst).Length - if ($srcSize -eq $dstSize) {{ - $copied = $true - break - }} - }} catch {{}} - Start-Sleep -Seconds 2 -}} +echo [%date% %time%] Process exited, waiting 3s... >> "%LOGFILE%" +timeout /t 3 /nobreak >nul -if (-not $copied) {{ exit 1 }} +rem Clean stale _MEI directories +echo [%date% %time%] Cleaning _MEI directories... >> "%LOGFILE%" +for /d %%D in ("%TMPDIR%\\_MEI*") do ( + rmdir /s /q "%%D" >nul 2>&1 +) +timeout /t 1 /nobreak >nul -Start-Sleep -Seconds 2 +rem Copy with retry +echo [%date% %time%] Starting copy... >> "%LOGFILE%" +set COPIED=0 +for /L %%i in (1,1,5) do ( + if !COPIED!==0 ( + copy /Y "%SRC%" "%DST%" >nul 2>&1 + if exist "%DST%" ( + echo [%date% %time%] Copy attempt %%i done >> "%LOGFILE%" + set COPIED=1 + ) else ( + echo [%date% %time%] Copy attempt %%i failed >> "%LOGFILE%" + timeout /t 2 /nobreak >nul + ) + ) +) -# Launch new exe via cmd start (clean environment, proper path handling) -Start-Process cmd.exe -ArgumentList '/c', 'start', '""', ('"{0}"' -f $dst) -WindowStyle Hidden +if %COPIED%==0 ( + echo [%date% %time%] FAILED: could not copy after 5 attempts >> "%LOGFILE%" + pause + goto cleanup +) -# Cleanup -Start-Sleep -Seconds 3 -Remove-Item -Path $src -Force -ErrorAction SilentlyContinue -Remove-Item -Path '{ps_path}' -Force -ErrorAction SilentlyContinue +echo [%date% %time%] Copy successful, launching... >> "%LOGFILE%" +timeout /t 2 /nobreak >nul + +rem Launch new exe +echo [%date% %time%] Starting: %DST% >> "%LOGFILE%" +start "" "%DST%" + +echo [%date% %time%] Launch command issued >> "%LOGFILE%" +timeout /t 2 /nobreak >nul + +:cleanup +rem Delete downloaded update file +del /f /q "%SRC%" >nul 2>&1 +echo [%date% %time%] Cleanup done >> "%LOGFILE%" + +rem Self-delete +del /f /q "%~f0" >nul 2>&1 """ - with open(ps_path, "w", encoding="utf-8") as f: - f.write(ps_content) + # Enable delayed expansion for variables inside for loops + bat_content = bat_content.replace("@echo off", + "@echo off\nsetlocal enabledelayedexpansion") - # VBS wrapper launches PowerShell hidden (no window flash) - vbs_content = ( - 'CreateObject("Wscript.Shell").Run ' - '"powershell -ExecutionPolicy Bypass -WindowStyle Hidden ' - f'-File ""{ps_path}""""", 0, False\n' + with open(bat_path, "w", encoding="utf-8") as f: + f.write(bat_content) + + log.info(f"Update BAT: {bat_path}, log: {log_path}") + + # Launch BAT minimized (not hidden — need cmd.exe to run) + subprocess.Popen( + ["cmd.exe", "/c", "start", "/min", "", bat_path], + creationflags=_SUBPROCESS_FLAGS, ) - with open(vbs_path, "w") as f: - f.write(vbs_content) - - os.startfile(vbs_path) return True except Exception as e: diff --git a/releases/ServerManager-v1.8.93-win-x64.exe b/releases/ServerManager-v1.8.93-win-x64.exe new file mode 100644 index 0000000..122c105 Binary files /dev/null and b/releases/ServerManager-v1.8.93-win-x64.exe differ diff --git a/version.py b/version.py index c671410..b585646 100755 --- a/version.py +++ b/version.py @@ -1,6 +1,6 @@ """Version info for ServerManager.""" -__version__ = "1.8.92" +__version__ = "1.8.93" __app_name__ = "ServerManager" __author__ = "aibot777" __description__ = "Desktop GUI for managing remote servers"