v1.8.93: rewrite update script from VBS+PowerShell to plain BAT with logging
VBS→PowerShell chain was silently failing. BAT is simpler, doesn't depend on execution policy, and writes detailed log to %TEMP%\sm_update.log for debugging. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
133
core/updater.py
133
core/updater.py
@@ -262,75 +262,98 @@ class UpdateChecker:
|
|||||||
return self._apply_linux(binary_path, current_exe)
|
return self._apply_linux(binary_path, current_exe)
|
||||||
|
|
||||||
def _apply_windows(self, new_exe: str, current_exe: str) -> bool:
|
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:
|
try:
|
||||||
tmp_dir = tempfile.gettempdir()
|
tmp_dir = tempfile.gettempdir()
|
||||||
ps_path = os.path.join(tmp_dir, "sm_update.ps1")
|
bat_path = os.path.join(tmp_dir, "sm_update.bat")
|
||||||
vbs_path = os.path.join(tmp_dir, "sm_update.vbs")
|
log_path = os.path.join(tmp_dir, "sm_update.log")
|
||||||
pid = os.getpid()
|
pid = os.getpid()
|
||||||
mei_dir = getattr(sys, '_MEIPASS', '')
|
|
||||||
exe_dir = os.path.dirname(current_exe)
|
|
||||||
|
|
||||||
ps_content = f"""
|
bat_content = f"""@echo off
|
||||||
$pid = {pid}
|
chcp 65001 >nul 2>&1
|
||||||
$src = '{new_exe}'
|
set "LOGFILE={log_path}"
|
||||||
$dst = '{current_exe}'
|
set "SRC={new_exe}"
|
||||||
$tempDir = '{tmp_dir}'
|
set "DST={current_exe}"
|
||||||
|
set "PID={pid}"
|
||||||
|
set "TMPDIR={tmp_dir}"
|
||||||
|
|
||||||
# Wait for old process to exit
|
echo [%date% %time%] Update script started >> "%LOGFILE%"
|
||||||
while (Get-Process -Id $pid -ErrorAction SilentlyContinue) {{
|
echo [%date% %time%] PID to wait for: %PID% >> "%LOGFILE%"
|
||||||
Start-Sleep -Seconds 1
|
echo [%date% %time%] SRC: %SRC% >> "%LOGFILE%"
|
||||||
}}
|
echo [%date% %time%] DST: %DST% >> "%LOGFILE%"
|
||||||
Start-Sleep -Seconds 3
|
|
||||||
|
|
||||||
# Clean ALL stale _MEI directories (best-effort, skip locked)
|
:wait_loop
|
||||||
try {{
|
tasklist /FI "PID eq %PID%" 2>nul | find "%PID%" >nul
|
||||||
Get-ChildItem -Path $tempDir -Directory -Filter '_MEI*' -ErrorAction SilentlyContinue | ForEach-Object {{
|
if %errorlevel%==0 (
|
||||||
Remove-Item -Path $_.FullName -Recurse -Force -ErrorAction SilentlyContinue
|
echo [%date% %time%] Waiting for PID %PID% to exit... >> "%LOGFILE%"
|
||||||
}}
|
timeout /t 1 /nobreak >nul
|
||||||
}} catch {{}}
|
goto wait_loop
|
||||||
Start-Sleep -Seconds 1
|
)
|
||||||
|
|
||||||
# Copy with retry
|
echo [%date% %time%] Process exited, waiting 3s... >> "%LOGFILE%"
|
||||||
$copied = $false
|
timeout /t 3 /nobreak >nul
|
||||||
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
|
|
||||||
}}
|
|
||||||
|
|
||||||
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)
|
if %COPIED%==0 (
|
||||||
Start-Process cmd.exe -ArgumentList '/c', 'start', '""', ('"{0}"' -f $dst) -WindowStyle Hidden
|
echo [%date% %time%] FAILED: could not copy after 5 attempts >> "%LOGFILE%"
|
||||||
|
pause
|
||||||
|
goto cleanup
|
||||||
|
)
|
||||||
|
|
||||||
# Cleanup
|
echo [%date% %time%] Copy successful, launching... >> "%LOGFILE%"
|
||||||
Start-Sleep -Seconds 3
|
timeout /t 2 /nobreak >nul
|
||||||
Remove-Item -Path $src -Force -ErrorAction SilentlyContinue
|
|
||||||
Remove-Item -Path '{ps_path}' -Force -ErrorAction SilentlyContinue
|
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:
|
# Enable delayed expansion for variables inside for loops
|
||||||
f.write(ps_content)
|
bat_content = bat_content.replace("@echo off",
|
||||||
|
"@echo off\nsetlocal enabledelayedexpansion")
|
||||||
|
|
||||||
# VBS wrapper launches PowerShell hidden (no window flash)
|
with open(bat_path, "w", encoding="utf-8") as f:
|
||||||
vbs_content = (
|
f.write(bat_content)
|
||||||
'CreateObject("Wscript.Shell").Run '
|
|
||||||
'"powershell -ExecutionPolicy Bypass -WindowStyle Hidden '
|
log.info(f"Update BAT: {bat_path}, log: {log_path}")
|
||||||
f'-File ""{ps_path}""""", 0, False\n'
|
|
||||||
|
# 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
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
BIN
releases/ServerManager-v1.8.93-win-x64.exe
Normal file
BIN
releases/ServerManager-v1.8.93-win-x64.exe
Normal file
Binary file not shown.
@@ -1,6 +1,6 @@
|
|||||||
"""Version info for ServerManager."""
|
"""Version info for ServerManager."""
|
||||||
|
|
||||||
__version__ = "1.8.92"
|
__version__ = "1.8.93"
|
||||||
__app_name__ = "ServerManager"
|
__app_name__ = "ServerManager"
|
||||||
__author__ = "aibot777"
|
__author__ = "aibot777"
|
||||||
__description__ = "Desktop GUI for managing remote servers"
|
__description__ = "Desktop GUI for managing remote servers"
|
||||||
|
|||||||
Reference in New Issue
Block a user