fix: версия в интерфейсе была зашита в разметке; установка падала на занятом файле
Версия. В index.html номер стоял руками в двух местах, а в app.js был
запасным значением '0.1.1'. Номер сборки приходил из API и обновлялся,
версия — нет: владелец обновился до e6eab12 и увидел v0.1.1. Подъём
версии в пяти местах бэкенда до экрана не доходил вовсе. Теперь версия
берётся только из API; если сервер её не передал, пишется Н/Д с причиной,
а не правдоподобный номер.
Установка. Отказ остановки прежнего хаба прерывал установку целиком, и
владелец получал голый код 15. Теперь неудачная остановка не отменяет
установку: причина показывается, работа продолжается, и если файл
действительно занят, об этом скажет копирование с именем файла.
Копирование файлов получило повтор: процесс мог не успеть отпустить файл
после остановки. Пять попыток с паузой вместо отказа с первой.
599 passed, ruff clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
e6eab12616
commit
b2ca7cdd4d
3 changed files with 45 additions and 12 deletions
|
|
@ -264,6 +264,19 @@ namespace HermesHubSetup
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restrict cleanup to this installation. Never kill arbitrary Python/browser processes.
|
// Restrict cleanup to this installation. Never kill arbitrary Python/browser processes.
|
||||||
|
public static string StopWarning = "";
|
||||||
|
|
||||||
|
// Процесс мог не успеть отпустить файл. Один отказ по занятости — не приговор.
|
||||||
|
static void CopyWithRetry(string source, string destination)
|
||||||
|
{
|
||||||
|
for (int attempt = 1; ; attempt++)
|
||||||
|
{
|
||||||
|
try { File.Copy(source, destination, true); return; }
|
||||||
|
catch (IOException) { if (attempt >= 5) throw; System.Threading.Thread.Sleep(700); }
|
||||||
|
catch (UnauthorizedAccessException) { if (attempt >= 5) throw; System.Threading.Thread.Sleep(700); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void StopOwnedRuntime(string home, bool includeLauncher)
|
public static void StopOwnedRuntime(string home, bool includeLauncher)
|
||||||
{
|
{
|
||||||
string escaped = Path.GetFullPath(home).TrimEnd('\\').Replace("'", "''");
|
string escaped = Path.GetFullPath(home).TrimEnd('\\').Replace("'", "''");
|
||||||
|
|
@ -296,7 +309,18 @@ namespace HermesHubSetup
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
StopOwnedRuntime(HermesHome, true);
|
// Неудачная остановка прежнего хаба не повод отменять установку.
|
||||||
|
// Раньше любой ненулевой выход скрипта останавливал всё, и владелец
|
||||||
|
// видел голый код 15. Если процесс уцелел, копирование само скажет,
|
||||||
|
// какой файл занят.
|
||||||
|
try { StopOwnedRuntime(HermesHome, true); }
|
||||||
|
catch (Exception stopEx)
|
||||||
|
{
|
||||||
|
StopWarning = stopEx.Message;
|
||||||
|
if (progressCallback != null)
|
||||||
|
progressCallback("Не удалось остановить прежний Hermes Hub: " + stopEx.Message
|
||||||
|
+ ". Продолжаю установку.", 5);
|
||||||
|
}
|
||||||
if (progressCallback != null) progressCallback("Preparing installation directory...", 10);
|
if (progressCallback != null) progressCallback("Preparing installation directory...", 10);
|
||||||
if (!Directory.Exists(TargetInstallDir))
|
if (!Directory.Exists(TargetInstallDir))
|
||||||
{
|
{
|
||||||
|
|
@ -313,8 +337,8 @@ namespace HermesHubSetup
|
||||||
|
|
||||||
if (File.Exists(launcherSrc))
|
if (File.Exists(launcherSrc))
|
||||||
{
|
{
|
||||||
File.Copy(launcherSrc, Path.Combine(TargetInstallDir, "HermesHub.exe"), true);
|
CopyWithRetry(launcherSrc, Path.Combine(TargetInstallDir, "HermesHub.exe"));
|
||||||
File.Copy(launcherSrc, Path.Combine(HermesHome, "HermesHub.exe"), true);
|
CopyWithRetry(launcherSrc, Path.Combine(HermesHome, "HermesHub.exe"));
|
||||||
}
|
}
|
||||||
|
|
||||||
string webLauncherSrc = Path.Combine(sourceRoot, @"launcher\HermesHubWeb.exe");
|
string webLauncherSrc = Path.Combine(sourceRoot, @"launcher\HermesHubWeb.exe");
|
||||||
|
|
@ -325,15 +349,15 @@ namespace HermesHubSetup
|
||||||
|
|
||||||
if (File.Exists(webLauncherSrc))
|
if (File.Exists(webLauncherSrc))
|
||||||
{
|
{
|
||||||
File.Copy(webLauncherSrc, Path.Combine(TargetInstallDir, "HermesHubWeb.exe"), true);
|
CopyWithRetry(webLauncherSrc, Path.Combine(TargetInstallDir, "HermesHubWeb.exe"));
|
||||||
File.Copy(webLauncherSrc, Path.Combine(HermesHome, "HermesHubWeb.exe"), true);
|
CopyWithRetry(webLauncherSrc, Path.Combine(HermesHome, "HermesHubWeb.exe"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy Setup.exe itself to target dir for uninstaller/repair
|
// Copy Setup.exe itself to target dir for uninstaller/repair
|
||||||
string setupSrc = Process.GetCurrentProcess().MainModule.FileName;
|
string setupSrc = Process.GetCurrentProcess().MainModule.FileName;
|
||||||
if (File.Exists(setupSrc))
|
if (File.Exists(setupSrc))
|
||||||
{
|
{
|
||||||
try { File.Copy(setupSrc, Path.Combine(TargetInstallDir, "HermesHubSetup.exe"), true); } catch { }
|
try { CopyWithRetry(setupSrc, Path.Combine(TargetInstallDir, "HermesHubSetup.exe")); } catch { }
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Install UI & System Dependencies into Hermes Python Environment
|
// 2. Install UI & System Dependencies into Hermes Python Environment
|
||||||
|
|
@ -392,7 +416,7 @@ namespace HermesHubSetup
|
||||||
string templateConfig = Path.Combine(sourceRoot, @"config\router_profiles.example.yaml");
|
string templateConfig = Path.Combine(sourceRoot, @"config\router_profiles.example.yaml");
|
||||||
if (!File.Exists(runtimeConfig) && File.Exists(templateConfig))
|
if (!File.Exists(runtimeConfig) && File.Exists(templateConfig))
|
||||||
{
|
{
|
||||||
File.Copy(templateConfig, runtimeConfig, true);
|
CopyWithRetry(templateConfig, runtimeConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6. Create Start Menu Shortcut
|
// 6. Create Start Menu Shortcut
|
||||||
|
|
@ -529,7 +553,7 @@ namespace HermesHubSetup
|
||||||
string fileName = Path.GetFileName(file);
|
string fileName = Path.GetFileName(file);
|
||||||
srcFiles.Add(fileName);
|
srcFiles.Add(fileName);
|
||||||
string destFile = Path.Combine(dst, fileName);
|
string destFile = Path.Combine(dst, fileName);
|
||||||
File.Copy(file, destFile, true);
|
CopyWithRetry(file, destFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove destination files that do not exist in source or are .pyc
|
// Remove destination files that do not exist in source or are .pyc
|
||||||
|
|
|
||||||
|
|
@ -2293,10 +2293,19 @@ function renderUpdateUI() {
|
||||||
const releaseMeta = document.getElementById('update-release-meta');
|
const releaseMeta = document.getElementById('update-release-meta');
|
||||||
const releaseNotes = document.getElementById('update-release-notes');
|
const releaseNotes = document.getElementById('update-release-notes');
|
||||||
|
|
||||||
const curVer = (latestUpdateInfo && latestUpdateInfo.current_version) || (currentSettings && currentSettings.version) || '0.1.1';
|
// Версия берётся ТОЛЬКО из API. Раньше номер был зашит в разметке и в
|
||||||
|
// запасном значении: подъём версии в коде до интерфейса не доходил, и
|
||||||
|
// владелец видел старый номер при новой сборке.
|
||||||
|
const curVer = (latestUpdateInfo && latestUpdateInfo.current_version) || (currentSettings && currentSettings.version) || '';
|
||||||
const cDisplay = installedCommit ? installedCommit.slice(0, 7) : 'неизвестно';
|
const cDisplay = installedCommit ? installedCommit.slice(0, 7) : 'неизвестно';
|
||||||
if (updateInfoDesc) {
|
if (updateInfoDesc) {
|
||||||
updateInfoDesc.textContent = `Hermes Hub v${curVer} (сборка: ${cDisplay})`;
|
updateInfoDesc.textContent = curVer
|
||||||
|
? `Hermes Hub v${curVer} (сборка: ${cDisplay})`
|
||||||
|
: `Hermes Hub (сборка: ${cDisplay}) — Н/Д: версия не передана сервером`;
|
||||||
|
}
|
||||||
|
const versionTag = document.getElementById('version-tag');
|
||||||
|
if (versionTag) {
|
||||||
|
versionTag.textContent = curVer ? `Hermes Hub Web v${curVer}` : 'Hermes Hub Web — Н/Д: версия не передана сервером';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (statusBadge) {
|
if (statusBadge) {
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@
|
||||||
<span class="status-dot healthy"></span>
|
<span class="status-dot healthy"></span>
|
||||||
<span class="source-text" id="source-text">Загрузка данных...</span>
|
<span class="source-text" id="source-text">Загрузка данных...</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="version-tag" id="version-tag">Hermes Hub Web v0.1.1</div>
|
<div class="version-tag" id="version-tag">Hermes Hub Web</div>
|
||||||
<div class="commit-tag" id="commit-tag" style="font-size:11px; color:var(--text-muted); font-family:var(--font-mono); margin-top:2px;">—</div>
|
<div class="commit-tag" id="commit-tag" style="font-size:11px; color:var(--text-muted); font-family:var(--font-mono); margin-top:2px;">—</div>
|
||||||
</div>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
@ -600,7 +600,7 @@
|
||||||
<div class="setting-row">
|
<div class="setting-row">
|
||||||
<div class="setting-info">
|
<div class="setting-info">
|
||||||
<div class="setting-label">Текущая версия и сборка</div>
|
<div class="setting-label">Текущая версия и сборка</div>
|
||||||
<div class="setting-desc" id="update-installed-info">Hermes Hub v0.1.1</div>
|
<div class="setting-desc" id="update-installed-info">Hermes Hub</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-control" style="display:flex; align-items:center; gap:8px;">
|
<div class="setting-control" style="display:flex; align-items:center; gap:8px;">
|
||||||
<span id="update-status-badge" class="badge">Не проверено</span>
|
<span id="update-status-badge" class="badge">Не проверено</span>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue