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:
139
core/updater.py
139
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
|
||||
|
||||
# Launch new exe via cmd start (clean environment, proper path handling)
|
||||
Start-Process cmd.exe -ArgumentList '/c', 'start', '""', ('"{0}"' -f $dst) -WindowStyle Hidden
|
||||
|
||||
# Cleanup
|
||||
Start-Sleep -Seconds 3
|
||||
Remove-Item -Path $src -Force -ErrorAction SilentlyContinue
|
||||
Remove-Item -Path '{ps_path}' -Force -ErrorAction SilentlyContinue
|
||||
"""
|
||||
with open(ps_path, "w", encoding="utf-8") as f:
|
||||
f.write(ps_content)
|
||||
|
||||
# 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'
|
||||
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
|
||||
)
|
||||
with open(vbs_path, "w") as f:
|
||||
f.write(vbs_content)
|
||||
)
|
||||
)
|
||||
|
||||
os.startfile(vbs_path)
|
||||
if %COPIED%==0 (
|
||||
echo [%date% %time%] FAILED: could not copy after 5 attempts >> "%LOGFILE%"
|
||||
pause
|
||||
goto cleanup
|
||||
)
|
||||
|
||||
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
|
||||
"""
|
||||
# Enable delayed expansion for variables inside for loops
|
||||
bat_content = bat_content.replace("@echo off",
|
||||
"@echo off\nsetlocal enabledelayedexpansion")
|
||||
|
||||
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,
|
||||
)
|
||||
return True
|
||||
|
||||
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__ = "1.8.92"
|
||||
__version__ = "1.8.93"
|
||||
__app_name__ = "ServerManager"
|
||||
__author__ = "aibot777"
|
||||
__description__ = "Desktop GUI for managing remote servers"
|
||||
|
||||
Reference in New Issue
Block a user