CLI приложения #25. Делаем настоящий установщик Windows
В прошлой части мы научились публиковать готовые приложения через GitHub Releases. Теперь пользователь может скачать архив, распаковать его и запустить программу. В общем-то, всё работает. Но согласитесь, не очень удобно каждый раз вручную раскладывать файлы по папкам, настраивать PATH, а при удалении вспоминать, что и куда мы скопировали.
Что ж, пора сделать нормальный установщик. Такой, чтобы запустил setup.exe, выбрал папку, нажал «Установить» — и всё готово.
И, кстати, всё, что мы сегодня рассмотрим, применимо не только к
CLI, но и к обычным настольным приложениям, напримерWinFormsилиWPF.
Что вообще делает установщик?#
На первый взгляд кажется, что он просто копирует файлы в нужную директорию. Отчасти так и есть, но этим его возможности не ограничиваются.
Обычно установщик может:
- Разместить файлы программы в нужных каталогах.
- Создать ярлыки в меню «Пуск» и на рабочем столе.
- Зарегистрировать приложение в
Windows, чтобы оно появилось в списке установленных программ. - Настроить переменные окружения, например
PATH. - Обеспечить корректное обновление и удаление приложения.
Причём не всё из перечисленного обязательно. Например, обычной CLI-утилите вряд ли нужен ярлык на рабочем столе, а вот возможность запускать её из любого каталога будет весьма полезной.
Куда устанавливать приложение?#
В Windows есть несколько стандартных каталогов, которые используются для разных целей.
Например:
C:\Program Files— программы, установленные для всех пользователей компьютера.%LOCALAPPDATA%— данные и приложения конкретного пользователя, не предназначенные для синхронизации между компьютерами.%APPDATA%— пользовательские данные, которые могут перемещаться вместе с профилем в корпоративной среде.%PROGRAMDATA%— общие данные приложения для всех пользователей.
Здесь важно не путать файлы самой программы с её настройками и пользовательскими данными. Например, исполняемый файл и библиотеки логично разместить в Program Files, а изменяемые настройки — в профиле пользователя. Почему? Потому что обычный пользователь не должен иметь возможность свободно изменять содержимое системного каталога установки.
И это актуально не только для CLI. Если вы разрабатываете WinForms-приложение, которое сохраняет настройки рядом со своим .exe, после установки в Program Files вполне можно столкнуться с проблемами доступа.
Знакомимся с Inno Setup#
Для создания установщика воспользуемся бесплатным инструментом Inno Setup. Он позволяет описать процесс установки специальным скриптом с расширением .iss, а затем собрать из него обычный setup.exe.
Скачать его можно с официального репозитория: https://github.com/jrsoftware/issrc
Сначала опубликуем наше CLI-приложение:
dotnet publish -c Release -r win-x64 --self-contained true -o ./publish/win-x64
На этот раз не будем использовать single-file, чтобы нагляднее показать, как установщик работает с несколькими файлами. После публикации получим папку с исполняемым файлом и зависимостями. Теперь создадим файл setup.iss рядом с проектом.
Описываем установку#
Начнём с простого примера:
#define AppName "MyApp"
#define AppVersion "1.0.0"
[Setup]
AppId=Demo.CliCourse.MyApp
AppName={#AppName}
AppVersion={#AppVersion}
DefaultDirName={autopf}\MyApp
DefaultGroupName=MyApp
OutputBaseFilename=MyApp-Setup
Compression=lzma
SolidCompression=yes
WizardStyle=modern
PrivilegesRequired=admin
[Files]
Source: "publish\win-x64\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
[Icons]
Name: "{group}\MyApp"; Filename: "{app}\MyApp.exe"; WorkingDir: "{app}"
Выглядит немного непривычно, но на самом деле здесь всё довольно просто.
- Секция
[Setup]содержит основные параметры установщика: название приложения, версию, каталог установки и настройки самого мастера. DefaultDirNameопределяет, куда по умолчанию будут установлены файлы. Константа{autopf}соответствует каталогу Program Files с учётом режима установки.PrivilegesRequired=adminозначает, что для установки потребуются права администратора.- Секция
[Files]отвечает за копирование файлов. В нашем случае мы берём всё содержимоеpublish\win-x64и переносим в каталог{app}, то есть туда, куда пользователь устанавливает приложение. - А
[Icons]создаёт ярлык в меню «Пуск».
Обратите внимание на AppId. Это идентификатор приложения, по которому Inno Setup связывает последующие установки с уже установленной программой. При обновлении его не нужно менять.
А как же удаление?#
Вот здесь начинается самое интересное. Inno Setup самостоятельно создаёт деинсталлятор и регистрирует программу в списке установленных приложений Windows. То есть нам не нужно вручную писать код удаления или создавать записи в реестре только ради появления приложения в настройках системы. При удалении Inno Setup использует журнал установки, чтобы убрать файлы и ярлыки, которые были установлены через его скрипт. Однако пользовательские файлы, созданные уже после установки, автоматически удалять не следует. Например, настройки, базы данных и документы могут понадобиться пользователю даже после удаления программы.
Собираем установщик#
Открываем setup.iss в Inno Setup Compiler и выбираем Build → Compile.
Если всё настроено правильно, получим файл:
MyApp-Setup.exe
Запускаем его и проходим обычный мастер установки.
После завершения приложение появится в списке установленных программ, а в меню «Пуск» будет создан ярлык.
Можно проверить и удаление: Windows запустит созданный Inno Setup деинсталлятор.
Но мы кое-что забыли#
Помните, что мы разрабатываем CLI-приложение? После установки в Program Files оно не станет автоматически доступным по команде myapp из любого каталога. Для этого нужно добавить путь к исполняемому файлу в PATH. И здесь уже возникают дополнительные вопросы: изменять пользовательскую или системную переменную? Как не затереть существующее значение? Как корректно удалить свой путь при деинсталляции? И что делать, если в PATH уже есть такой каталог? А ещё неплохо бы научиться устанавливать приложение без прав администратора, правильно обрабатывать обновления и сохранять пользовательские данные.
В следующей части продолжим разбираться с Inno Setup и доведём установщик до более законченного состояния.
Ну а пока у нас уже есть настоящий setup.exe, который устанавливает приложение, регистрирует его в Windows и умеет корректно удалять.