summaryrefslogtreecommitdiffstats
path: root/packaging/windows
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--packaging/windows/NetdataWhite.icobin0 -> 15134 bytes
-rwxr-xr-x[-rw-r--r--]packaging/windows/bash_execute.sh (renamed from packaging/utils/bash_execute.sh)0
-rw-r--r--packaging/windows/build.ps116
-rw-r--r--packaging/windows/clion-msys-mingw64-environment.bat (renamed from packaging/utils/clion-msys-mingw64-environment.bat)0
-rw-r--r--packaging/windows/clion-msys-msys-environment.bat (renamed from packaging/utils/clion-msys-msys-environment.bat)0
-rwxr-xr-xpackaging/windows/compile-on-windows.sh60
-rwxr-xr-xpackaging/windows/fetch-msys2-installer.py101
-rw-r--r--packaging/windows/functions.ps131
-rw-r--r--packaging/windows/install-dependencies.ps184
-rw-r--r--packaging/windows/installer.nsi186
-rw-r--r--packaging/windows/invoke-msys2.ps116
-rwxr-xr-xpackaging/windows/msys2-dependencies.sh50
-rwxr-xr-xpackaging/windows/package-windows.sh51
-rw-r--r--packaging/windows/package.ps116
-rw-r--r--packaging/windows/protoc.bat (renamed from packaging/utils/protoc.bat)0
-rw-r--r--packaging/windows/win-build-dir.sh20
-rw-r--r--packaging/windows/windows-openssh-to-msys.bat (renamed from packaging/utils/windows-openssh-to-msys.bat)0
17 files changed, 631 insertions, 0 deletions
diff --git a/packaging/windows/NetdataWhite.ico b/packaging/windows/NetdataWhite.ico
new file mode 100644
index 000000000..857b88062
--- /dev/null
+++ b/packaging/windows/NetdataWhite.ico
Binary files differ
diff --git a/packaging/utils/bash_execute.sh b/packaging/windows/bash_execute.sh
index 4092db966..4092db966 100644..100755
--- a/packaging/utils/bash_execute.sh
+++ b/packaging/windows/bash_execute.sh
diff --git a/packaging/windows/build.ps1 b/packaging/windows/build.ps1
new file mode 100644
index 000000000..f656ed568
--- /dev/null
+++ b/packaging/windows/build.ps1
@@ -0,0 +1,16 @@
+# Run the build
+
+#Requires -Version 4.0
+
+$ErrorActionPreference = "Stop"
+
+. "$PSScriptRoot\functions.ps1"
+
+$msysbash = Get-MSYS2Bash "$msysprefix"
+$env:CHERE_INVOKING = 'yes'
+
+& $msysbash -l "$PSScriptRoot\compile-on-windows.sh"
+
+if ($LastExitcode -ne 0) {
+ exit 1
+}
diff --git a/packaging/utils/clion-msys-mingw64-environment.bat b/packaging/windows/clion-msys-mingw64-environment.bat
index 19035d8eb..19035d8eb 100644
--- a/packaging/utils/clion-msys-mingw64-environment.bat
+++ b/packaging/windows/clion-msys-mingw64-environment.bat
diff --git a/packaging/utils/clion-msys-msys-environment.bat b/packaging/windows/clion-msys-msys-environment.bat
index 9f0c095d3..9f0c095d3 100644
--- a/packaging/utils/clion-msys-msys-environment.bat
+++ b/packaging/windows/clion-msys-msys-environment.bat
diff --git a/packaging/windows/compile-on-windows.sh b/packaging/windows/compile-on-windows.sh
new file mode 100755
index 000000000..ceb4f5502
--- /dev/null
+++ b/packaging/windows/compile-on-windows.sh
@@ -0,0 +1,60 @@
+#!/bin/bash
+
+REPO_ROOT="$(dirname "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" > /dev/null && pwd -P)")")"
+CMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE:-RelWithDebInfo}"
+
+# shellcheck source=./win-build-dir.sh
+. "${REPO_ROOT}/packaging/windows/win-build-dir.sh"
+
+set -exu -o pipefail
+
+if [ -d "${build}" ]; then
+ rm -rf "${build}"
+fi
+
+generator="Unix Makefiles"
+build_args="-j $(nproc)"
+
+if command -v ninja >/dev/null 2>&1; then
+ generator="Ninja"
+ build_args="-k 1"
+fi
+
+COMMON_CFLAGS="-Wa,-mbig-obj -pipe -D_FILE_OFFSET_BITS=64 -D__USE_MINGW_ANSI_STDIO=1"
+
+if [ "${CMAKE_BUILD_TYPE}" = "Debug" ]; then
+ BUILD_CFLAGS="-fstack-protector-all -O0 -ggdb -Wall -Wextra -Wno-char-subscripts -DNETDATA_INTERNAL_CHECKS=1 ${COMMON_CFLAGS} ${CFLAGS:-}"
+else
+ BUILD_CFLAGS="-O2 ${COMMON_CFLAGS} ${CFLAGS:-}"
+fi
+
+${GITHUB_ACTIONS+echo "::group::Configuring"}
+# shellcheck disable=SC2086
+CFLAGS="${BUILD_CFLAGS}" /usr/bin/cmake \
+ -S "${REPO_ROOT}" \
+ -B "${build}" \
+ -G "${generator}" \
+ -DCMAKE_INSTALL_PREFIX="/opt/netdata" \
+ -DBUILD_FOR_PACKAGING=On \
+ -DNETDATA_USER="${USER}" \
+ -DENABLE_ACLK=On \
+ -DENABLE_CLOUD=On \
+ -DENABLE_H2O=Off \
+ -DENABLE_ML=On \
+ -DENABLE_PLUGIN_GO=On \
+ -DENABLE_EXPORTER_PROMETHEUS_REMOTE_WRITE=Off \
+ -DENABLE_BUNDLED_JSONC=On \
+ -DENABLE_BUNDLED_PROTOBUF=Off \
+ ${EXTRA_CMAKE_OPTIONS:-}
+${GITHUB_ACTIONS+echo "::endgroup::"}
+
+${GITHUB_ACTIONS+echo "::group::Building"}
+# shellcheck disable=SC2086
+cmake --build "${build}" -- ${build_args}
+${GITHUB_ACTIONS+echo "::endgroup::"}
+
+if [ -t 1 ]; then
+ echo
+ echo "Compile with:"
+ echo "cmake --build \"${build}\""
+fi
diff --git a/packaging/windows/fetch-msys2-installer.py b/packaging/windows/fetch-msys2-installer.py
new file mode 100755
index 000000000..e30e7205c
--- /dev/null
+++ b/packaging/windows/fetch-msys2-installer.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python
+
+'''Fetch the MSYS2 installer.'''
+
+from __future__ import annotations
+
+import hashlib
+import json
+import shutil
+import sys
+
+from pathlib import Path
+from tempfile import TemporaryDirectory
+from typing import Final
+from urllib.request import Request, urlopen
+
+REPO: Final = 'msys2/msys2-installer'
+
+
+def get_latest_release() -> tuple[str, str]:
+ '''Get the latest release for the repo.'''
+ REQUEST: Final = Request(
+ url=f'https://api.github.com/repos/{REPO}/releases',
+ headers={
+ 'Accept': 'application/vnd.github+json',
+ 'X-GitHub-API-Version': '2022-11-28',
+ },
+ method='GET',
+ )
+
+ print('>>> Fetching release list')
+
+ with urlopen(REQUEST, timeout=15) as response:
+ if response.status != 200:
+ print(f'!!! Failed to fetch release list, status={response.status}')
+ sys.exit(1)
+
+ data = json.load(response)
+
+ data = list(filter(lambda x: x['name'] != 'Nightly Installer Build', data))
+
+ name = data[0]['name']
+ version = data[0]['tag_name'].replace('-', '')
+
+ return name, version
+
+
+def fetch_release_asset(tmpdir: Path, name: str, file: str) -> Path:
+ '''Fetch a specific release asset.'''
+ REQUEST: Final = Request(
+ url=f'https://github.com/{REPO}/releases/download/{name}/{file}',
+ method='GET',
+ )
+ TARGET: Final = tmpdir / file
+
+ print(f'>>> Downloading {file}')
+
+ with urlopen(REQUEST, timeout=15) as response:
+ if response.status != 200:
+ print(f'!!! Failed to fetch {file}, status={response.status}')
+ sys.exit(1)
+
+ TARGET.write_bytes(response.read())
+
+ return TARGET
+
+
+def main() -> None:
+ '''Core program logic.'''
+ if len(sys.argv) != 2:
+ print(f'{__file__} must be run with exactly one argument.')
+
+ target = Path(sys.argv[1])
+ tmp_target = target.with_name(f'.{target.name}.tmp')
+
+ name, version = get_latest_release()
+
+ with TemporaryDirectory() as tmpdir:
+ tmppath = Path(tmpdir)
+
+ installer = fetch_release_asset(tmppath, name, f'msys2-base-x86_64-{version}.tar.zst')
+ checksums = fetch_release_asset(tmppath, name, f'msys2-base-x86_64-{version}.tar.zst.sha256')
+
+ print('>>> Verifying SHA256 checksum')
+ expected_checksum = checksums.read_text().partition(' ')[0].casefold()
+ actual_checksum = hashlib.sha256(installer.read_bytes()).hexdigest().casefold()
+
+ if expected_checksum != actual_checksum:
+ print('!!! Checksum mismatch')
+ print(f'!!! Expected: {expected_checksum}')
+ print(f'!!! Actual: {actual_checksum}')
+ sys.exit(1)
+
+ print(f'>>> Copying to {target}')
+
+ shutil.copy(installer, tmp_target)
+ tmp_target.replace(target)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/packaging/windows/functions.ps1 b/packaging/windows/functions.ps1
new file mode 100644
index 000000000..a5f032daa
--- /dev/null
+++ b/packaging/windows/functions.ps1
@@ -0,0 +1,31 @@
+# Functions used by the PowerShell scripts in this directory.
+
+#Requires -Version 4.0
+
+function Get-MSYS2Prefix {
+ if (-Not ($msysprefix)) {
+ if (Test-Path -Path C:\msys64\usr\bin\bash.exe) {
+ return "C:\msys64"
+ } elseif ($env:ChocolateyToolsLocation) {
+ if (Test-Path -Path "$env:ChocolateyToolsLocation\msys64\usr\bin\bash.exe") {
+ Write-Host "Found MSYS2 installed via Chocolatey"
+ Write-Host "This will work for building Netdata, but not for packaging it"
+ return "$env:ChocolateyToolsLocation\msys64"
+ }
+ }
+ }
+
+ return ""
+}
+
+function Get-MSYS2Bash {
+ $msysprefix = $args[0]
+
+ if (-Not ($msysprefix)) {
+ $msysprefix = Get-MSYS2Prefix
+ }
+
+ Write-Host "Using MSYS2 from $msysprefix"
+
+ return "$msysprefix\usr\bin\bash.exe"
+}
diff --git a/packaging/windows/install-dependencies.ps1 b/packaging/windows/install-dependencies.ps1
new file mode 100644
index 000000000..66ec73160
--- /dev/null
+++ b/packaging/windows/install-dependencies.ps1
@@ -0,0 +1,84 @@
+# Set up Windows build dependencies.
+#
+# This script first sees if msys is installed. If so, it just uses it. If not, it tries to bootstrap it with chocolatey or winget.
+
+#Requires -Version 4.0
+
+$ErrorActionPreference = "Stop"
+
+. "$PSScriptRoot\functions.ps1"
+
+$msysprefix = Get-MSYS2Prefix
+
+function Check-FileHash {
+ $file_path = $args[0]
+
+ Write-Host "Checking SHA256 hash of $file_path"
+
+ $actual_hash = (Get-FileHash -Algorithm SHA256 -Path $file_path).Hash.toLower()
+ $expected_hash = (Get-Content "$file_path.sha256").split()[0]
+
+ if ($actual_hash -ne $expected_hash) {
+ Write-Host "SHA256 hash mismatch!"
+ Write-Host "Expected: $expected_hash"
+ Write-Host "Actual: $actual_hash"
+ exit 1
+ }
+}
+
+function Install-MSYS2 {
+ $repo = 'msys2/msys2-installer'
+ $uri = "https://api.github.com/repos/$repo/releases"
+ $headers = @{
+ 'Accept' = 'application/vnd.github+json'
+ 'X-GitHub-API-Version' = '2022-11-28'
+ }
+ $installer_path = "$env:TEMP\msys2-base.exe"
+
+ if ($env:PROCESSOR_ARCHITECTURE -ne "AMD64") {
+ Write-Host "We can only install MSYS2 for 64-bit x86 systems, but you appear to have a different processor architecture ($env:PROCESSOR_ARCHITECTURE)."
+ Write-Host "You will need to install MSYS2 yourself instead."
+ exit 1
+ }
+
+ Write-Host "Determining latest release"
+ $release_list = Invoke-RestMethod -Uri $uri -Headers $headers -TimeoutSec 30
+
+ $release = $release_list[0]
+ $release_name = $release.name
+ $version = $release.tag_name.Replace('-', '')
+ $installer_url = "https://github.com/$repo/releases/download/$release_name/msys2-x86_64-$version.exe"
+
+ Write-Host "Fetching $installer_url"
+ Invoke-WebRequest $installer_url -OutFile $installer_path
+ Write-Host "Fetching $installer_url.sha256"
+ Invoke-WebRequest "$installer_url.sha256" -OutFile "$installer_path.sha256"
+
+ Write-Host "Checking file hash"
+ Check-FileHash $installer_path
+
+ Write-Host "Installing"
+ & $installer_path in --confirm-command --accept-messages --root C:/msys64
+
+ return "C:\msys64"
+}
+
+if (-Not ($msysprefix)) {
+ Write-Host "Could not find MSYS2, attempting to install it"
+ $msysprefix = Install-MSYS2
+}
+
+$msysbash = Get-MSYS2Bash "$msysprefix"
+$env:CHERE_INVOKING = 'yes'
+
+& $msysbash -l "$PSScriptRoot\msys2-dependencies.sh"
+
+if ($LastExitcode -ne 0) {
+ Write-Host "First update attempt failed. This is expected if the msys-runtime package needed updated, trying again."
+
+ & $msysbash -l "$PSScriptRoot\msys2-dependencies.sh"
+
+ if ($LastExitcode -ne 0) {
+ exit 1
+ }
+}
diff --git a/packaging/windows/installer.nsi b/packaging/windows/installer.nsi
new file mode 100644
index 000000000..88d160a1d
--- /dev/null
+++ b/packaging/windows/installer.nsi
@@ -0,0 +1,186 @@
+!include "MUI2.nsh"
+!include "nsDialogs.nsh"
+!include "FileFunc.nsh"
+
+Name "Netdata"
+Outfile "netdata-installer.exe"
+InstallDir "$PROGRAMFILES\Netdata"
+RequestExecutionLevel admin
+
+!define MUI_ICON "NetdataWhite.ico"
+!define MUI_UNICON "NetdataWhite.ico"
+
+!define ND_UININSTALL_REG "Software\Microsoft\Windows\CurrentVersion\Uninstall\Netdata"
+
+!define MUI_ABORTWARNING
+!define MUI_UNABORTWARNING
+
+!insertmacro MUI_PAGE_WELCOME
+!insertmacro MUI_PAGE_LICENSE "C:\msys64\cloud.txt"
+!insertmacro MUI_PAGE_LICENSE "C:\msys64\gpl-3.0.txt"
+!insertmacro MUI_PAGE_DIRECTORY
+!insertmacro MUI_PAGE_INSTFILES
+Page Custom NetdataConfigPage NetdataConfigLeave
+!insertmacro MUI_PAGE_FINISH
+
+!insertmacro MUI_UNPAGE_CONFIRM
+!insertmacro MUI_UNPAGE_INSTFILES
+!insertmacro MUI_UNPAGE_FINISH
+
+!insertmacro MUI_LANGUAGE "English"
+
+var hStartMsys
+var startMsys
+
+var hCloudToken
+var cloudToken
+var hCloudRoom
+var cloudRoom
+
+Function .onInit
+ nsExec::ExecToLog '$SYSDIR\sc.exe stop Netdata'
+ pop $0
+ ${If} $0 == 0
+ nsExec::ExecToLog '$SYSDIR\sc.exe delete Netdata'
+ pop $0
+ ${EndIf}
+
+ StrCpy $startMsys ${BST_UNCHECKED}
+FunctionEnd
+
+Function NetdataConfigPage
+ !insertmacro MUI_HEADER_TEXT "Netdata configuration" "Claim your agent on Netdata Cloud"
+
+ nsDialogs::Create 1018
+ Pop $0
+ ${If} $0 == error
+ Abort
+ ${EndIf}
+
+ ${NSD_CreateLabel} 0 0 100% 12u "Enter your Token and Cloud Room."
+ ${NSD_CreateLabel} 0 15% 100% 12u "Optionally, you can open a terminal to execute additional commands."
+
+ ${NSD_CreateLabel} 0 35% 20% 10% "Token"
+ Pop $0
+ ${NSD_CreateText} 21% 35% 79% 10% ""
+ Pop $hCloudToken
+
+ ${NSD_CreateLabel} 0 55% 20% 10% "Room"
+ Pop $0
+ ${NSD_CreateText} 21% 55% 79% 10% ""
+ Pop $hCloudRoom
+
+ ${NSD_CreateCheckbox} 0 70% 100% 10u "Open terminal"
+ Pop $hStartMsys
+ nsDialogs::Show
+FunctionEnd
+
+Function NetdataConfigLeave
+ ${NSD_GetText} $hCloudToken $cloudToken
+ ${NSD_GetText} $hCloudRoom $cloudRoom
+ ${NSD_GetState} $hStartMsys $startMsys
+
+ StrLen $0 $cloudToken
+ StrLen $1 $cloudRoom
+ ${If} $0 == 125
+ ${AndIf} $0 == 36
+ # We should start our new claiming software here
+ MessageBox MB_OK "$cloudToken | $cloudRoom | $startMsys"
+ ${EndIf}
+
+ ${If} $startMsys == 1
+ nsExec::ExecToLog '$INSTDIR\msys2.exe'
+ pop $0
+ ${EndIf}
+FunctionEnd
+
+Function NetdataUninstallRegistry
+ ClearErrors
+ WriteRegStr HKLM "${ND_UININSTALL_REG}" \
+ "DisplayName" "Netdata - Real-time system monitoring."
+ WriteRegStr HKLM "${ND_UININSTALL_REG}" \
+ "DisplayIcon" "$INSTDIR\Uninstall.exe,0"
+ WriteRegStr HKLM "${ND_UININSTALL_REG}" \
+ "UninstallString" "$INSTDIR\Uninstall.exe"
+ WriteRegStr HKLM "${ND_UININSTALL_REG}" \
+ "RegOwner" "Netdata Inc."
+ WriteRegStr HKLM "${ND_UININSTALL_REG}" \
+ "RegCompany" "Netdata Inc."
+ WriteRegStr HKLM "${ND_UININSTALL_REG}" \
+ "Publisher" "Netdata Inc."
+ WriteRegStr HKLM "${ND_UININSTALL_REG}" \
+ "HelpLink" "https://learn.netdata.cloud/"
+ WriteRegStr HKLM "${ND_UININSTALL_REG}" \
+ "URLInfoAbout" "https://www.netdata.cloud/"
+ WriteRegStr HKLM "${ND_UININSTALL_REG}" \
+ "DisplayVersion" "${CURRVERSION}"
+ WriteRegStr HKLM "${ND_UININSTALL_REG}" \
+ "VersionMajor" "${MAJORVERSION}"
+ WriteRegStr HKLM "${ND_UININSTALL_REG}" \
+ "VersionMinor" "${MINORVERSION}"
+
+ IfErrors 0 +2
+ MessageBox MB_ICONEXCLAMATION|MB_OK "Unable to create an entry in the Control Panel!" IDOK end
+
+ ClearErrors
+ ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2
+ IntFmt $0 "0x%08X" $0
+ WriteRegDWORD HKLM "${ND_UININSTALL_REG}" "EstimatedSize" "$0"
+
+ IfErrors 0 +2
+ MessageBox MB_ICONEXCLAMATION|MB_OK "Cannot estimate the installation size." IDOK end
+ end:
+FunctionEnd
+
+Section "Install Netdata"
+ SetOutPath $INSTDIR
+ SetCompress off
+
+ File /r "C:\msys64\opt\netdata\*.*"
+
+ ClearErrors
+ nsExec::ExecToLog '$SYSDIR\sc.exe create Netdata binPath= "$INSTDIR\usr\bin\netdata.exe" start= delayed-auto'
+ pop $0
+ ${If} $0 != 0
+ DetailPrint "Warning: Failed to create Netdata service."
+ ${EndIf}
+
+ ClearErrors
+ nsExec::ExecToLog '$SYSDIR\sc.exe description Netdata "Real-time system monitoring service"'
+ pop $0
+ ${If} $0 != 0
+ DetailPrint "Warning: Failed to add Netdata service description."
+ ${EndIf}
+
+ ClearErrors
+ nsExec::ExecToLog '$SYSDIR\sc.exe start Netdata'
+ pop $0
+ ${If} $0 != 0
+ DetailPrint "Warning: Failed to start Netdata service."
+ ${EndIf}
+
+ WriteUninstaller "$INSTDIR\Uninstall.exe"
+
+ Call NetdataUninstallRegistry
+SectionEnd
+
+Section "Uninstall"
+ ClearErrors
+ nsExec::ExecToLog '$SYSDIR\sc.exe stop Netdata'
+ pop $0
+ ${If} $0 != 0
+ DetailPrint "Warning: Failed to stop Netdata service."
+ ${EndIf}
+
+ ClearErrors
+ nsExec::ExecToLog '$SYSDIR\sc.exe delete Netdata'
+ pop $0
+ ${If} $0 != 0
+ DetailPrint "Warning: Failed to delete Netdata service."
+ ${EndIf}
+
+ RMDir /r "$INSTDIR"
+
+ DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Netdata"
+SectionEnd
+
diff --git a/packaging/windows/invoke-msys2.ps1 b/packaging/windows/invoke-msys2.ps1
new file mode 100644
index 000000000..bffa7f90b
--- /dev/null
+++ b/packaging/windows/invoke-msys2.ps1
@@ -0,0 +1,16 @@
+# Invoke the specified script using MSYS2
+
+#Requires -Version 4.0
+
+$ErrorActionPreference = "Stop"
+
+. "$PSScriptRoot\functions.ps1"
+
+$msysbash = Get-MSYS2Bash "$msysprefix"
+$env:CHERE_INVOKING = 'yes'
+
+& $msysbash -l $args[0]
+
+if ($LastExitcode -ne 0) {
+ exit 1
+}
diff --git a/packaging/windows/msys2-dependencies.sh b/packaging/windows/msys2-dependencies.sh
new file mode 100755
index 000000000..95a1952df
--- /dev/null
+++ b/packaging/windows/msys2-dependencies.sh
@@ -0,0 +1,50 @@
+#!/bin/bash
+#
+# Install the dependencies we need to build Netdata on MSYS2
+
+. /etc/profile
+
+set -euo pipefail
+
+${GITHUB_ACTIONS+echo "::group::Updating MSYS2"}
+pacman -Syuu --noconfirm
+${GITHUB_ACTIONS+echo "::endgroup::"}
+
+${GITHUB_ACTIONS+echo "::group::Installing dependencies"}
+pacman -S --noconfirm --needed \
+ base-devel \
+ cmake \
+ git \
+ liblz4-devel \
+ libutil-linux \
+ libutil-linux-devel \
+ libyaml-devel \
+ libzstd-devel \
+ mingw64/mingw-w64-x86_64-brotli \
+ mingw64/mingw-w64-x86_64-go \
+ mingw64/mingw-w64-x86_64-libuv \
+ mingw64/mingw-w64-x86_64-lz4 \
+ mingw64/mingw-w64-x86_64-nsis \
+ mingw64/mingw-w64-x86_64-openssl \
+ mingw64/mingw-w64-x86_64-pcre2 \
+ mingw64/mingw-w64-x86_64-protobuf \
+ mingw64/mingw-w64-x86_64-zlib \
+ mingw-w64-ucrt-x86_64-toolchain \
+ mingw-w64-x86_64-toolchain \
+ msys2-devel \
+ msys/brotli-devel \
+ msys/libuv-devel \
+ msys/pcre2-devel \
+ msys/zlib-devel \
+ openssl-devel \
+ protobuf-devel \
+ python \
+ ucrt64/mingw-w64-ucrt-x86_64-brotli \
+ ucrt64/mingw-w64-ucrt-x86_64-go \
+ ucrt64/mingw-w64-ucrt-x86_64-libuv \
+ ucrt64/mingw-w64-ucrt-x86_64-lz4 \
+ ucrt64/mingw-w64-ucrt-x86_64-openssl \
+ ucrt64/mingw-w64-ucrt-x86_64-pcre2 \
+ ucrt64/mingw-w64-ucrt-x86_64-protobuf \
+ ucrt64/mingw-w64-ucrt-x86_64-zlib
+${GITHUB_ACTIONS+echo "::endgroup::"}
diff --git a/packaging/windows/package-windows.sh b/packaging/windows/package-windows.sh
new file mode 100755
index 000000000..03f72a692
--- /dev/null
+++ b/packaging/windows/package-windows.sh
@@ -0,0 +1,51 @@
+#!/bin/bash
+
+repo_root="$(dirname "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" > /dev/null && pwd -P)")")"
+
+if [ -n "${BUILD_DIR}" ]; then
+ build="${BUILD_DIR}"
+elif [ -n "${OSTYPE}" ]; then
+ if [ -n "${MSYSTEM}" ]; then
+ build="${repo_root}/build-${OSTYPE}-${MSYSTEM}"
+ else
+ build="${repo_root}/build-${OSTYPE}"
+ fi
+elif [ "$USER" = "vk" ]; then
+ build="${repo_root}/build"
+else
+ build="${repo_root}/build"
+fi
+
+set -exu -o pipefail
+
+${GITHUB_ACTIONS+echo "::group::Installing"}
+cmake --install "${build}"
+${GITHUB_ACTIONS+echo "::endgroup::"}
+
+if [ ! -f "/msys2-latest.tar.zst" ]; then
+ ${GITHUB_ACTIONS+echo "::group::Fetching MSYS2 files"}
+ "${repo_root}/packaging/windows/fetch-msys2-installer.py" /msys2-latest.tar.zst
+ ${GITHUB_ACTIONS+echo "::endgroup::"}
+fi
+
+${GITHUB_ACTIONS+echo "::group::Licenses"}
+if [ ! -f "/gpl-3.0.txt" ]; then
+ curl -o /gpl-3.0.txt "https://www.gnu.org/licenses/gpl-3.0.txt"
+fi
+
+if [ ! -f "/cloud.txt" ]; then
+ curl -o /cloud.txt "https://raw.githubusercontent.com/netdata/netdata/master/src/web/gui/v2/LICENSE.md"
+fi
+${GITHUB_ACTIONS+echo "::endgroup::"}
+
+${GITHUB_ACTIONS+echo "::group::Packaging"}
+tar -xf /msys2-latest.tar.zst -C /opt/netdata/ || exit 1
+cp -R /opt/netdata/msys64/* /opt/netdata/ || exit 1
+rm -rf /opt/netdata/msys64/
+NDVERSION=$"$(grep 'CMAKE_PROJECT_VERSION:STATIC' "${build}/CMakeCache.txt"| cut -d= -f2)"
+NDMAJORVERSION=$"$(grep 'CMAKE_PROJECT_VERSION_MAJOR:STATIC' "${build}/CMakeCache.txt"| cut -d= -f2)"
+NDMINORVERSION=$"$(grep 'CMAKE_PROJECT_VERSION_MINOR:STATIC' "${build}/CMakeCache.txt"| cut -d= -f2)"
+
+/mingw64/bin/makensis.exe -DCURRVERSION="${NDVERSION}" -DMAJORVERSION="${NDMAJORVERSION}" -DMINORVERSION="${NDMINORVERSION}" "${repo_root}/packaging/windows/installer.nsi"
+${GITHUB_ACTIONS+echo "::endgroup::"}
+
diff --git a/packaging/windows/package.ps1 b/packaging/windows/package.ps1
new file mode 100644
index 000000000..828e105f1
--- /dev/null
+++ b/packaging/windows/package.ps1
@@ -0,0 +1,16 @@
+# Package the build
+
+#Requires -Version 4.0
+
+$ErrorActionPreference = "Stop"
+
+. "$PSScriptRoot\functions.ps1"
+
+$msysbash = Get-MSYS2Bash "$msysprefix"
+$env:CHERE_INVOKING = 'yes'
+
+& $msysbash -l "$PSScriptRoot\package-windows.sh"
+
+if ($LastExitcode -ne 0) {
+ exit 1
+}
diff --git a/packaging/utils/protoc.bat b/packaging/windows/protoc.bat
index fe7a76f27..fe7a76f27 100644
--- a/packaging/utils/protoc.bat
+++ b/packaging/windows/protoc.bat
diff --git a/packaging/windows/win-build-dir.sh b/packaging/windows/win-build-dir.sh
new file mode 100644
index 000000000..09dd6b977
--- /dev/null
+++ b/packaging/windows/win-build-dir.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+if [ -n "${BUILD_DIR}" ]; then
+ if (echo "${BUILD_DIR}" | grep -q -E "^[A-Z]:\\\\"); then
+ build="$(echo "${BUILD_DIR}" | sed -e 's/\\/\//g' -e 's/^\([A-Z]\):\//\/\1\//' -)"
+ else
+ build="${BUILD_DIR}"
+ fi
+elif [ -n "${OSTYPE}" ]; then
+ if [ -n "${MSYSTEM}" ]; then
+ build="${REPO_ROOT}/build-${OSTYPE}-${MSYSTEM}"
+ else
+ build="${REPO_ROOT}/build-${OSTYPE}"
+ fi
+elif [ "$USER" = "vk" ]; then
+ build="${REPO_ROOT}/build"
+else
+ # shellcheck disable=SC2034
+ build="${REPO_ROOT}/build"
+fi
diff --git a/packaging/utils/windows-openssh-to-msys.bat b/packaging/windows/windows-openssh-to-msys.bat
index 829cb4845..829cb4845 100644
--- a/packaging/utils/windows-openssh-to-msys.bat
+++ b/packaging/windows/windows-openssh-to-msys.bat