mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-05-08 14:33:23 +00:00
feat: msi installer and cli command (#2020)
* feat: Add msi quite installer * chore: update code for new wix * feat: add cpack wix installer * feat: add gihub workflow for msi * chore: fix deploy script * chore: add wix logs * chore: fix msi build * chore: fix msi build * chore: add wix exts log * chore: add cpackwixpatch for registering the service * chore: fix build script * chore: fix wix fragment * feat: add closing app with reinstalling * chore: update version for test * chore: fix build script * feat: added cli commands --connect and --import (#1967) * fix: delete unused file and disable rollback after unsuccessful service start in msi installer * fix: Add deps to msi * fix: msi deps * feat: added os signal handler * fix: incorrect import at the empty client start (#2024) * chore: add force quit for os signal handler * feat: os signal handler improvements * fix: fixed --connection command --------- Co-authored-by: Mykola Baibuz <mykola.baibuz@gmail.com> Co-authored-by: aiamnezia <ai@amnezia.org> Co-authored-by: Mitternacht822 <sb@amnezia.org>
This commit is contained in:
23
.github/workflows/deploy.yml
vendored
23
.github/workflows/deploy.yml
vendored
@@ -139,12 +139,28 @@ jobs:
|
||||
with:
|
||||
arch: 'x64'
|
||||
|
||||
- name: 'Setup .NET SDK'
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '8.0.x'
|
||||
|
||||
- name: 'Install WiX Toolset'
|
||||
shell: powershell
|
||||
run: |
|
||||
dotnet tool install --global wix --version 4.0.6
|
||||
wix extension add -g WixToolset.UI.wixext/4.0.6
|
||||
wix extension add -g WixToolset.Util.wixext/4.0.6
|
||||
wix extension list -g
|
||||
$wixBinDir = Join-Path $env:USERPROFILE ".dotnet\tools"
|
||||
echo "WIX_BIN_DIR=$wixBinDir" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
||||
|
||||
- name: 'Build project'
|
||||
shell: cmd
|
||||
run: |
|
||||
set BUILD_ARCH=${{ env.BUILD_ARCH }}
|
||||
set QT_BIN_DIR="${{ runner.temp }}\\Qt\\${{ env.QT_VERSION }}\\msvc2019_64\\bin"
|
||||
set QIF_BIN_DIR="${{ runner.temp }}\\Qt\\Tools\\QtInstallerFramework\\${{ env.QIF_VERSION }}\\bin"
|
||||
set WIX_BIN_DIR=%USERPROFILE%\.dotnet\tools
|
||||
call deploy\\build_windows.bat
|
||||
|
||||
- name: 'Rename Windows installer'
|
||||
@@ -159,6 +175,13 @@ jobs:
|
||||
path: AmneziaVPN_${{ env.VERSION }}_x64.exe
|
||||
retention-days: 7
|
||||
|
||||
- name: 'Upload MSI installer artifact'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: AmneziaVPN_Windows_MSI_installer
|
||||
path: AmneziaVPN_x${{ env.BUILD_ARCH }}.msi
|
||||
retention-days: 7
|
||||
|
||||
- name: 'Upload unpacked artifact'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
|
||||
@@ -49,3 +49,36 @@ if(NOT IOS AND NOT ANDROID AND NOT MACOS_NE)
|
||||
|
||||
include(${CMAKE_SOURCE_DIR}/deploy/installer/config.cmake)
|
||||
endif()
|
||||
|
||||
set(AMNEZIA_STAGE_DIR "${CMAKE_BINARY_DIR}/stage")
|
||||
|
||||
if(WIN32 AND NOT IOS AND NOT ANDROID AND NOT MACOS_NE)
|
||||
file(TO_CMAKE_PATH "${AMNEZIA_STAGE_DIR}" AMNEZIA_STAGE_DIR_CMAKE)
|
||||
|
||||
set(CPACK_GENERATOR "WIX")
|
||||
set(CPACK_WIX_VERSION 4)
|
||||
set(CPACK_PACKAGE_NAME "AmneziaVPN")
|
||||
set(CPACK_PACKAGE_VENDOR "AmneziaVPN")
|
||||
set(CPACK_PACKAGE_VERSION ${AMNEZIAVPN_VERSION})
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "AmneziaVPN client")
|
||||
set(CPACK_PACKAGE_INSTALL_DIRECTORY "AmneziaVPN")
|
||||
set(CPACK_PACKAGE_DIRECTORY "${CMAKE_BINARY_DIR}")
|
||||
set(CPACK_PACKAGE_EXECUTABLES "AmneziaVPN" "AmneziaVPN")
|
||||
set(CPACK_WIX_UPGRADE_GUID "{2D55AC62-96D6-4692-8C05-0D85BBF95485}")
|
||||
set(CPACK_WIX_PRODUCT_ICON "${CMAKE_SOURCE_DIR}/client/images/app.ico")
|
||||
|
||||
# WiX patches
|
||||
set(_AMNEZIA_WIX_PATCH_SERVICE "${CMAKE_SOURCE_DIR}/deploy/installer/wix/service_install_patch.xml")
|
||||
set(_AMNEZIA_WIX_PATCH_CLOSE_APP "${CMAKE_SOURCE_DIR}/deploy/installer/wix/close_client_patch.xml")
|
||||
file(TO_CMAKE_PATH "${_AMNEZIA_WIX_PATCH_SERVICE}" _AMNEZIA_WIX_PATCH_SERVICE_CMAKE)
|
||||
file(TO_CMAKE_PATH "${_AMNEZIA_WIX_PATCH_CLOSE_APP}" _AMNEZIA_WIX_PATCH_CLOSE_APP_CMAKE)
|
||||
set(CPACK_WIX_PATCH_FILE "${_AMNEZIA_WIX_PATCH_SERVICE_CMAKE};${_AMNEZIA_WIX_PATCH_CLOSE_APP_CMAKE}")
|
||||
|
||||
# WiX v4 Util extension for CloseApplication + namespace for util
|
||||
set(CPACK_WIX_EXTENSIONS "${CPACK_WIX_EXTENSIONS};WixToolset.Util.wixext")
|
||||
set(CPACK_WIX_CUSTOM_XMLNS "util=http://wixtoolset.org/schemas/v4/wxs/util")
|
||||
|
||||
set(CPACK_INSTALLED_DIRECTORIES "${AMNEZIA_STAGE_DIR_CMAKE};/")
|
||||
|
||||
include(CPack)
|
||||
endif()
|
||||
|
||||
@@ -27,9 +27,13 @@
|
||||
#include <QtQuick/QQuickWindow> // for QQuickWindow
|
||||
#include <QWindow> // for qobject_cast<QWindow*>
|
||||
|
||||
bool AmneziaApplication::m_forceQuit = false;
|
||||
|
||||
AmneziaApplication::AmneziaApplication(int &argc, char *argv[]) : AMNEZIA_BASE_CLASS(argc, argv),
|
||||
m_optAutostart({QStringLiteral("a"), QStringLiteral("autostart")}, QStringLiteral("System autostart")),
|
||||
m_optCleanup ({QStringLiteral("c"), QStringLiteral("cleanup")}, QStringLiteral("Cleanup logs"))
|
||||
m_optCleanup ({QStringLiteral("c"), QStringLiteral("cleanup")}, QStringLiteral("Cleanup logs")),
|
||||
m_optConnect ({QStringLiteral("connect")}, QStringLiteral("Connect to server by index on startup"), QStringLiteral("index")),
|
||||
m_optImport ({QStringLiteral("import")}, QStringLiteral("Import configuration from data string"), QStringLiteral("data"))
|
||||
{
|
||||
setQuitOnLastWindowClosed(false);
|
||||
|
||||
@@ -126,6 +130,16 @@ void AmneziaApplication::init()
|
||||
m_coreController.reset(new CoreController(m_vpnConnection, m_settings, m_engine));
|
||||
|
||||
m_engine->addImportPath("qrc:/ui/qml/Modules/");
|
||||
|
||||
if (m_parser.isSet(m_optImport)) {
|
||||
const QString data = m_parser.value(m_optImport);
|
||||
if (!data.isEmpty()) {
|
||||
if (m_coreController) {
|
||||
m_coreController->importConfigFromData(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_engine->load(url);
|
||||
|
||||
m_coreController->setQmlRoot();
|
||||
@@ -165,6 +179,18 @@ void AmneziaApplication::init()
|
||||
}
|
||||
});
|
||||
#endif
|
||||
|
||||
if (m_parser.isSet(m_optConnect)) {
|
||||
bool ok = false;
|
||||
int idx = m_parser.value(m_optConnect).toInt(&ok);
|
||||
if (ok) {
|
||||
QTimer::singleShot(0, this, [this, idx]() {
|
||||
if (m_coreController) {
|
||||
m_coreController->openConnectionByIndex(idx);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AmneziaApplication::registerTypes()
|
||||
@@ -211,6 +237,8 @@ bool AmneziaApplication::parseCommands()
|
||||
|
||||
m_parser.addOption(m_optAutostart);
|
||||
m_parser.addOption(m_optCleanup);
|
||||
m_parser.addOption(m_optConnect);
|
||||
m_parser.addOption(m_optImport);
|
||||
|
||||
m_parser.process(*this);
|
||||
|
||||
@@ -247,8 +275,12 @@ bool AmneziaApplication::eventFilter(QObject *watched, QEvent *event)
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
||||
quit();
|
||||
#else
|
||||
if (m_coreController && m_coreController->pageController()) {
|
||||
m_coreController->pageController()->hideMainWindow();
|
||||
if (m_forceQuit) {
|
||||
quit();
|
||||
} else {
|
||||
if (m_coreController && m_coreController->pageController()) {
|
||||
m_coreController->pageController()->hideMainWindow();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return true; // eat the close
|
||||
@@ -257,6 +289,12 @@ bool AmneziaApplication::eventFilter(QObject *watched, QEvent *event)
|
||||
return QObject::eventFilter(watched, event);
|
||||
}
|
||||
|
||||
void AmneziaApplication::forceQuit()
|
||||
{
|
||||
m_forceQuit = true;
|
||||
quit();
|
||||
}
|
||||
|
||||
QQmlApplicationEngine *AmneziaApplication::qmlEngine() const
|
||||
{
|
||||
return m_engine;
|
||||
|
||||
@@ -45,7 +45,11 @@ public:
|
||||
QNetworkAccessManager *networkManager();
|
||||
QClipboard *getClipboard();
|
||||
|
||||
public slots:
|
||||
void forceQuit();
|
||||
|
||||
private:
|
||||
static bool m_forceQuit;
|
||||
QQmlApplicationEngine *m_engine {};
|
||||
std::shared_ptr<Settings> m_settings;
|
||||
|
||||
@@ -58,6 +62,8 @@ private:
|
||||
|
||||
QCommandLineOption m_optAutostart;
|
||||
QCommandLineOption m_optCleanup;
|
||||
QCommandLineOption m_optConnect;
|
||||
QCommandLineOption m_optImport;
|
||||
|
||||
QSharedPointer<VpnConnection> m_vpnConnection;
|
||||
QThread m_vpnConnectionThread;
|
||||
|
||||
@@ -411,3 +411,22 @@ QSharedPointer<PageController> CoreController::pageController() const
|
||||
{
|
||||
return m_pageController;
|
||||
}
|
||||
|
||||
void CoreController::openConnectionByIndex(int serverIndex)
|
||||
{
|
||||
if (m_serversModel) {
|
||||
m_serversModel->setProcessedServerIndex(serverIndex);
|
||||
m_serversModel->setDefaultServerIndex(serverIndex);
|
||||
}
|
||||
m_connectionController->toggleConnection();
|
||||
}
|
||||
|
||||
void CoreController::importConfigFromData(const QString &data)
|
||||
{
|
||||
if (!m_importController)
|
||||
return;
|
||||
|
||||
if (m_importController->extractConfigFromData(data)) {
|
||||
m_importController->importConfig();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,9 @@ public:
|
||||
QSharedPointer<PageController> pageController() const;
|
||||
void setQmlRoot();
|
||||
|
||||
void openConnectionByIndex(int serverIndex);
|
||||
void importConfigFromData(const QString &data);
|
||||
|
||||
signals:
|
||||
void translationsUpdated();
|
||||
void websiteUrlChanged(const QString &newUrl);
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
#include "osSignalHandler.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QMetaObject>
|
||||
#include <QSocketNotifier>
|
||||
|
||||
#include "../amnezia_application.h"
|
||||
|
||||
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
@@ -15,7 +18,8 @@
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <QMetaObject>
|
||||
#include <QAbstractNativeEventFilter>
|
||||
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
@@ -25,21 +29,30 @@ namespace
|
||||
static bool initialized = false;
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
static BOOL WINAPI consoleHandler(DWORD signal)
|
||||
class WindowsCloseFilter : public QAbstractNativeEventFilter
|
||||
{
|
||||
switch (signal) {
|
||||
case CTRL_CLOSE_EVENT:
|
||||
case CTRL_C_EVENT:
|
||||
case CTRL_BREAK_EVENT:
|
||||
case CTRL_LOGOFF_EVENT:
|
||||
case CTRL_SHUTDOWN_EVENT:
|
||||
if (QCoreApplication::instance()) {
|
||||
QMetaObject::invokeMethod(QCoreApplication::instance(), "quit", Qt::QueuedConnection);
|
||||
public:
|
||||
bool nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result) override
|
||||
{
|
||||
MSG *msg = static_cast<MSG *>(message);
|
||||
|
||||
switch (msg->message) {
|
||||
case WM_CLOSE: {
|
||||
const HWND active = GetActiveWindow();
|
||||
const HWND self = msg->hwnd;
|
||||
if (active != self) {
|
||||
AmneziaApplication *app = qobject_cast<AmneziaApplication *>(QCoreApplication::instance());
|
||||
if (app) {
|
||||
QMetaObject::invokeMethod(app, "forceQuit", Qt::QueuedConnection);
|
||||
}
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
default: return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
};
|
||||
|
||||
static WindowsCloseFilter *windowsFilter = nullptr;
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
|
||||
@@ -70,14 +83,16 @@ namespace
|
||||
}
|
||||
});
|
||||
}
|
||||
#elif defined(Q_OS_MACX)
|
||||
#elif defined(Q_OS_MACOS)
|
||||
static int signalPipe[2] = { -1, -1 };
|
||||
static QSocketNotifier *socketNotifier = nullptr;
|
||||
|
||||
static void macSignalHandler(int)
|
||||
{
|
||||
const char ch = 1;
|
||||
::write(signalPipe[1], &ch, sizeof(ch));
|
||||
if (signalPipe[1] >= 0) {
|
||||
const char ch = 1;
|
||||
::write(signalPipe[1], &ch, sizeof(ch));
|
||||
}
|
||||
}
|
||||
|
||||
static void setupUnixSignalHandler()
|
||||
@@ -88,14 +103,6 @@ namespace
|
||||
::fcntl(signalPipe[0], F_SETFL, O_NONBLOCK);
|
||||
::fcntl(signalPipe[1], F_SETFL, O_NONBLOCK);
|
||||
|
||||
struct sigaction sa {};
|
||||
sa.sa_handler = macSignalHandler;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
|
||||
sigaction(SIGINT, &sa, nullptr);
|
||||
sigaction(SIGTERM, &sa, nullptr);
|
||||
|
||||
socketNotifier = new QSocketNotifier(signalPipe[0], QSocketNotifier::Read, QCoreApplication::instance());
|
||||
|
||||
QObject::connect(socketNotifier, &QSocketNotifier::activated, QCoreApplication::instance(), [](int) {
|
||||
@@ -103,6 +110,14 @@ namespace
|
||||
::read(signalPipe[0], buf, sizeof(buf));
|
||||
QCoreApplication::quit();
|
||||
});
|
||||
|
||||
struct sigaction sa {};
|
||||
sa.sa_handler = macSignalHandler;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
|
||||
sigaction(SIGINT, &sa, nullptr);
|
||||
sigaction(SIGTERM, &sa, nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -111,6 +126,8 @@ namespace
|
||||
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
|
||||
if (socketNotifier) {
|
||||
socketNotifier->setEnabled(false);
|
||||
socketNotifier->deleteLater();
|
||||
socketNotifier = nullptr;
|
||||
}
|
||||
|
||||
if (signalFd >= 0) {
|
||||
@@ -119,8 +136,17 @@ namespace
|
||||
}
|
||||
|
||||
#elif defined(Q_OS_MACOS)
|
||||
struct sigaction sa {};
|
||||
sa.sa_handler = SIG_DFL;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
sigaction(SIGINT, &sa, nullptr);
|
||||
sigaction(SIGTERM, &sa, nullptr);
|
||||
|
||||
if (socketNotifier) {
|
||||
socketNotifier->setEnabled(false);
|
||||
socketNotifier->deleteLater();
|
||||
socketNotifier = nullptr;
|
||||
}
|
||||
|
||||
if (signalPipe[0] >= 0) {
|
||||
@@ -133,6 +159,14 @@ namespace
|
||||
signalPipe[1] = -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
if (windowsFilter) {
|
||||
QCoreApplication::instance()->removeNativeEventFilter(windowsFilter);
|
||||
delete windowsFilter;
|
||||
windowsFilter = nullptr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,12 +181,13 @@ void OsSignalHandler::setup()
|
||||
|
||||
initialized = true;
|
||||
|
||||
#if (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) || defined(Q_OS_MACX)
|
||||
#if (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) || defined(Q_OS_MACOS)
|
||||
setupUnixSignalHandler();
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
SetConsoleCtrlHandler(consoleHandler, TRUE);
|
||||
windowsFilter = new WindowsCloseFilter();
|
||||
QCoreApplication::instance()->installNativeEventFilter(windowsFilter);
|
||||
#endif
|
||||
|
||||
QObject::connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, [] { cleanupUnixSignalHandler(); });
|
||||
|
||||
@@ -8,6 +8,21 @@ set PATH=%QT_BIN_DIR:"=%;%PATH%
|
||||
|
||||
echo "Using Qt in %QT_BIN_DIR%"
|
||||
echo "Using QIF in %QIF_BIN_DIR%"
|
||||
echo "Using WiX in %WIX_BIN_DIR%"
|
||||
|
||||
if "%WIX_BIN_DIR%"=="" (
|
||||
echo "WIX_BIN_DIR is not set"
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
set WIX_BIN_DIR_UNQUOTED=%WIX_BIN_DIR:"=%
|
||||
|
||||
set WIX_CLI=%WIX_BIN_DIR_UNQUOTED%\wix.exe
|
||||
|
||||
if not exist "%WIX_CLI%" (
|
||||
echo "WiX CLI (wix.exe) was not found in %WIX_BIN_DIR%"
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
REM Hold on to current directory
|
||||
set PROJECT_DIR=%cd%
|
||||
@@ -22,6 +37,8 @@ set PREBILT_DEPLOY_DATA_DIR=%PROJECT_DIR:"=%\client\3rd-prebuilt\deploy-prebuilt
|
||||
set DEPLOY_DATA_DIR=%SCRIPT_DIR:"=%\data\windows\x%BUILD_ARCH:"=%
|
||||
set INSTALLER_DATA_DIR=%WORK_DIR:"=%\installer\packages\%APP_DOMAIN:"=%\data
|
||||
set TARGET_FILENAME=%PROJECT_DIR:"=%\%APP_NAME:"=%_x%BUILD_ARCH:"=%.exe
|
||||
set TARGET_MSI_FILENAME=%PROJECT_DIR:"=%\%APP_NAME:"=%_x%BUILD_ARCH:"=%.msi
|
||||
set STAGE_DIR=%WORK_DIR:"=%\stage
|
||||
|
||||
echo "Environment:"
|
||||
echo "WORK_DIR: %WORK_DIR%"
|
||||
@@ -32,10 +49,14 @@ echo "OUT_APP_DIR: %OUT_APP_DIR%"
|
||||
echo "DEPLOY_DATA_DIR: %DEPLOY_DATA_DIR%"
|
||||
echo "INSTALLER_DATA_DIR: %INSTALLER_DATA_DIR%"
|
||||
echo "TARGET_FILENAME: %TARGET_FILENAME%"
|
||||
echo "TARGET_MSI_FILENAME: %TARGET_MSI_FILENAME%"
|
||||
echo "STAGE_DIR: %STAGE_DIR%"
|
||||
|
||||
echo "Cleanup..."
|
||||
rmdir /Q /S %WORK_DIR%
|
||||
del %TARGET_FILENAME%
|
||||
del %TARGET_MSI_FILENAME%
|
||||
rmdir /Q /S "%STAGE_DIR%"
|
||||
|
||||
mkdir %WORK_DIR%
|
||||
|
||||
@@ -56,6 +77,7 @@ mkdir "%OUT_APP_DIR%"
|
||||
copy "%WORK_DIR%\service\server\release\%APP_NAME%-service.exe" "%OUT_APP_DIR%"
|
||||
rem copy "%WORK_DIR%\client\%APP_FILENAME%" "%OUT_APP_DIR%"
|
||||
|
||||
copy /Y "%PROJECT_DIR%\client\images\app.ico" "%OUT_APP_DIR%\AmneziaVPN.ico" >nul
|
||||
|
||||
echo "Signing exe"
|
||||
cd %OUT_APP_DIR%
|
||||
@@ -89,5 +111,38 @@ timeout 5
|
||||
cd %PROJECT_DIR%
|
||||
signtool sign /v /n "Privacy Technologies OU" /fd sha256 /tr http://timestamp.comodoca.com/?td=sha256 /td sha256 "%TARGET_FILENAME%"
|
||||
|
||||
echo "Finished, see %TARGET_FILENAME%"
|
||||
echo "Preparing staging directory for MSI..."
|
||||
rmdir /Q /S "%STAGE_DIR%"
|
||||
mkdir "%STAGE_DIR%"
|
||||
xcopy "%OUT_APP_DIR%" "%STAGE_DIR%" /s /e /y /i /f >nul
|
||||
|
||||
echo "Building MSI via CPack..."
|
||||
rmdir /Q /S "%WORK_DIR%\_CPack_Packages"
|
||||
cd %WORK_DIR%
|
||||
cpack -G WIX -C Release --config "%WORK_DIR%\CPackConfig.cmake"
|
||||
if exist "%WORK_DIR%\_CPack_Packages\win64\WIX\wix.log" (
|
||||
echo ---------------------------------------------
|
||||
echo Contents of wix.log:
|
||||
type "%WORK_DIR%\_CPack_Packages\win64\WIX\wix.log"
|
||||
echo ---------------------------------------------
|
||||
)
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
set GENERATED_MSI=
|
||||
for /f "delims=" %%i in ('dir /b /a:-d /o:-d "%WORK_DIR%\*.msi"') do (
|
||||
if not defined GENERATED_MSI set GENERATED_MSI=%WORK_DIR%\%%i
|
||||
)
|
||||
|
||||
if "%GENERATED_MSI%"=="" (
|
||||
echo "Failed to locate generated MSI package"
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
copy /Y "%GENERATED_MSI%" "%TARGET_MSI_FILENAME%"
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
cd %PROJECT_DIR%
|
||||
signtool sign /v /n "Privacy Technologies OU" /fd sha256 /tr http://timestamp.comodoca.com/?td=sha256 /td sha256 "%TARGET_MSI_FILENAME%"
|
||||
|
||||
echo "Finished, see %TARGET_FILENAME% and %TARGET_MSI_FILENAME%"
|
||||
exit 0
|
||||
|
||||
13
deploy/installer/wix/close_client_patch.xml
Normal file
13
deploy/installer/wix/close_client_patch.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<CPackWiXPatch>
|
||||
<CPackWiXFragment Id="#PRODUCT">
|
||||
<!-- Требует расширение WixToolset.Util.wixext и xmlns util -->
|
||||
<util:CloseApplication
|
||||
Id="CloseAmneziaClient"
|
||||
Target="AmneziaVPN.exe"
|
||||
Description="Closing AmneziaVPN client"
|
||||
TerminateProcess="1"
|
||||
RebootPrompt="no" />
|
||||
</CPackWiXFragment>
|
||||
</CPackWiXPatch>
|
||||
|
||||
24
deploy/installer/wix/service_install_patch.xml
Normal file
24
deploy/installer/wix/service_install_patch.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<CPackWiXPatch>
|
||||
<CPackWiXFragment Id="CM_CP_AmneziaVPN_service.exe">
|
||||
<ServiceInstall
|
||||
Id="AmneziaServiceInstall"
|
||||
Name="AmneziaVPN-service"
|
||||
DisplayName="AmneziaVPN Service"
|
||||
Description="Service for AmneziaVPN"
|
||||
Start="auto"
|
||||
Type="ownProcess"
|
||||
ErrorControl="normal"
|
||||
Vital="no">
|
||||
<ServiceDependency Id="BFE" />
|
||||
<ServiceDependency Id="nsi" />
|
||||
</ServiceInstall>
|
||||
<ServiceControl
|
||||
Id="AmneziaServiceControl"
|
||||
Name="AmneziaVPN-service"
|
||||
Start="install"
|
||||
Stop="both"
|
||||
Remove="uninstall"
|
||||
Wait="yes" />
|
||||
</CPackWiXFragment>
|
||||
</CPackWiXPatch>
|
||||
Reference in New Issue
Block a user