Мы написали свой установщик, и NeuroSquad теперь обновляется сам
За день установщик похудел с 550 до 96 МБ, а потом был переписан с нуля. Что было не так со старым и как обновления теперь ставятся, ни разу не ломая вашу копию.
NeuroSquad 0.1.100 — первая версия, которая сама следит за своей актуальностью. Путь сюда занял три выпуска меньше чем за сутки и дал самый полезный урок недели: установщик — часть продукта. Это первое окно, которое видят люди, и когда он ломается, он ломается в худшем месте — между старой версией, которой уже нет, и новой, которой ещё нет.
С 550 МБ до 96
Первый публичный установщик весил 550 МБ. Большую часть занимала модель диктовки — около 640 МБ в распакованном виде; её положили внутрь, чтобы голосовой ввод работал сразу после запуска. Но диктовка — вещь необязательная, и заставлять всех качать её ради того, чтобы попробовать холст с агентами, было неудачным компромиссом.
В 0.1.92 модель из установщика убрали. Теперь она скачивается, когда вы её попросите, — на шаге «Диктовка» мастера настройки или позже в настройках, — а диктовка включается сама, как только загрузка закончится, без перезапуска. До тех пор строка состояния пишет «Диктовка: скачайте модель», а не показывает ошибку. Установщик похудел примерно до 110 МБ.
Остальное нашлось в менее эффектном месте — в том, что упаковывается. Упаковщик целиком копирует каждую рабочую зависимость приложения, а десктопное приложение перечисляло там весь стек интерфейса — библиотеки компонентов, наборы иконок, инструментарий доступности, — хотя сборщик и так вкомпилирует всё это в страницу. Перенос всего, что нужно только странице, из рантайм-зависимостей сэкономил около 70 МБ файлов, которые никто никогда не загружал. 0.1.94 вышел на 96 МБ.
Почему сгенерированному установщику пришлось уйти
Первые установщики генерировал инструмент упаковки, и два бага в них были настолько неприятными, что оправдали написание собственного.
Первый: он отказывался ставиться с сообщением «NeuroSquad не может быть закрыт», хотя NeuroSquad уже был закрыт. Проверка звучала как «запущен ли хоть какой-то процесс из папки установки» — без имён. А запущенными оставались консольные хосты терминалов из карточек агентов, пережившие выход из приложения. Их не было видно, сообщение их не называло, и нажать было не на что.
Второй был хуже: прерванная установка могла оставить после себя недописанное приложение. В одном случае это был neurosquad.exe на 8 МБ вместо 200 — и никакой записи в списке приложений Windows, через которую его можно было бы удалить.
Новый установщик
Это небольшая WPF-программа для .NET Framework 4.8, который уже входит в Windows 10 и 11, так что заранее ничего ставить не нужно. Сам исполняемый файл весит около 240 КБ; приложение дописано к нему LZMA-архивом, нарезанным на блоки по 32 МБ, которые упаковываются и распаковываются параллельно, с CRC-32 для каждого файла. Сборка один раз скачивает свой компилятор C# и сверяет его с закреплённым SHA-256; SDK на машине сборки тоже не нужен.
Отличается он в основном тем, что говорит вам правду:
- Живой журнал каждого шага — в окне и в файле в
%TEMP%, так что у любого сбоя есть строка, на которую можно показать пальцем. - Мешающие процессы перечислены по имени и PID и завершаются только по нажатию кнопки. Никаких догадок и тихих убийств.
- Обновление никогда не пишет поверх. Новая версия распаковывается рядом со старой, проверяется, и папки меняются местами, только когда всё на месте. Сбой или отмена оставляют старую версию ровно такой, какой она была.
- Удаление убирает то, что было установлено, — файлы из списка, составленного при установке, ярлыки и запись в «Приложениях». Ваши данные удаляются, только если вы поставите галочку.
Одна деталь невидима и при этом обязательна: ярлык в меню «Пуск» должен нести AppUserModelID приложения. Без него Windows не доставляет всплывающие уведомления приложения — а «ваш агент ждёт вас» и есть то уведомление, вокруг которого построен весь продукт.
Проверять установщик на машине, где ведётся разработка, рискованно, поэтому у него есть два ключа как раз для этого. --snapshot сохраняет каждую страницу в PNG на любом из трёх языков. --sandbox кладёт ярлыки и запись «Приложений» в папку вместо меню «Пуск» и реестра, так что установку, обновление и удаление можно прогнать от начала до конца, не трогая систему.
Обновления, которые ставятся сами
Когда установщик умеет безопасно заменить работающую копию, автообновление становится возможным. NeuroSquad проверяет новый выпуск при каждом запуске и раз в час, скачивает его в фоне и сверяет SHA-256 с контрольной суммой, которую публикует сам выпуск. Нет контрольной суммы — нет установки.
Обновления не отключаются; выбираете вы только время. Кольцо в заголовке окна показывает загрузку, затем значок с точкой позволяет обновиться в любой момент, а диалог один раз на версию спрашивает: сейчас или при следующем запуске. «Сейчас» закрывает приложение и передаёт работу установщику, который дожидается выхода приложения, ставит новую версию поверх и запускает её. Следующий запуск ставит известную более новую версию ещё до открытия приложения — а если сети нет, после трёх попыток сдаётся и открывает ту версию, что есть.
Скачивается NeuroSquad 0.1.108
0.0 из 99.5 МБ
Когда скачается, можно обновиться сразу или при следующем запуске.
Баг, который нашла проверка обновления
Обновление проверяли по-настоящему: две сборки, локальная лента выпусков, обновление при запуске, обновление посреди работы приложения и запуск без сети с уже скачанным обновлением. С «Обновить сейчас» новая версия появлялась на экране примерно через десять секунд.
А до этого первый прогон упал — на обмене папок. Что-то всё ещё держало папку установки, и это было не приложение. Это был тот же осиротевший консольный хост, что сбивал с толку старый установщик: дочерний процесс терминала карточки, у которого рабочей папкой была папка установки — потому что оттуда было запущено само приложение. Процесса, для которого папка является текущей, достаточно, чтобы Windows не дала её переименовать.
Исправление — одна строка в самом начале запуска приложения: сменить рабочую папку на домашнюю. Дочерние процессы её наследуют, и папка установки больше ни для кого не текущая. Вторую половину закрыл 0.1.108: при обновлении со старой версии, чьи оставшиеся терминалы всё ещё держат папку, установщик теперь показывает их вместе с остальными процессами, а если файл держит что-то, что он не может опознать, — например, окно Проводника, — он не сдаётся, а заменяет файлы по одному и возвращает всё как было, если какой-то шаг не удался.
Установщик — единственная часть приложения, которую нельзя исправить следующим обновлением. Он должен работать правильно, пока ничего другого не запущено.
Если у вас 0.1.94 или старше, один раз запустите новый установщик поверх — дальше обновления будут приходить сами. Всё, что изменилось, — в журнале изменений 0.1.100.


