diff --git a/assets/windows/bf_installer_icon.ico b/assets/windows/bf_installer_icon.ico new file mode 100644 index 00000000..e07486af Binary files /dev/null and b/assets/windows/bf_installer_icon.ico differ diff --git a/assets/windows/bf_uninstaller_icon.ico b/assets/windows/bf_uninstaller_icon.ico new file mode 100644 index 00000000..02a79b2f Binary files /dev/null and b/assets/windows/bf_uninstaller_icon.ico differ diff --git a/assets/windows/installer.nsi b/assets/windows/installer.nsi new file mode 100644 index 00000000..098947fd --- /dev/null +++ b/assets/windows/installer.nsi @@ -0,0 +1,91 @@ +!include "MUI2.nsh" + +# Receives variables from the command line +# ${VERSION} - Version to generate (x.y.z) +# ${PLATFORM} - Platform to generate (win32 or win64) +# ${DEST_FOLDER} - Destination folder for the installer files + +# Some definitions +!define SOURCE_FILES "..\..\apps\betaflight-configurator\${PLATFORM}\*" +!define APP_NAME "Betaflight Configurator" +!define COMPANY_NAME "The Betaflight open source project." +!define GROUP_NAME "Betaflight" +!define FOLDER_NAME "Betaflight-Configurator" +!define FILE_NAME_INSTALLER "betaflight-configurator-installer-${VERSION}-${PLATFORM}.exe" +!define FILE_NAME_UNINSTALLER "uninstall-betaflight-configurator.exe" +!define FILE_NAME_EXECUTABLE "betaflight-configurator.exe" +!define LICENSE "..\..\LICENSE" + + +Name "${APP_NAME}" +BrandingText "${COMPANY_NAME}" + +# set the icon +!define MUI_ICON ".\bf_installer_icon.ico" +!define MUI_UNICON ".\bf_uninstaller_icon.ico" + +# define the resulting installer's name: +OutFile "..\..\${DEST_FOLDER}\${FILE_NAME_INSTALLER}" + +# set the default installation directory +!if ${PLATFORM} == 'win64' + InstallDir "$PROGRAMFILES64\${GROUP_NAME}\${FOLDER_NAME}\" +!else + InstallDir "$PROGRAMFILES\${GROUP_NAME}\${FOLDER_NAME}\" +!endif + +# app dialogs +!insertmacro MUI_PAGE_WELCOME +!insertmacro MUI_PAGE_LICENSE ${LICENSE} +!insertmacro MUI_PAGE_DIRECTORY +!insertmacro MUI_PAGE_INSTFILES + +!define MUI_FINISHPAGE_RUN "$INSTDIR\${FILE_NAME_EXECUTABLE}" + +!insertmacro MUI_PAGE_FINISH +!insertmacro MUI_LANGUAGE "English" +!insertmacro MUI_LANGUAGE "Catalan" +!insertmacro MUI_LANGUAGE "French" +!insertmacro MUI_LANGUAGE "German" +!insertmacro MUI_LANGUAGE "Korean" +!insertmacro MUI_LANGUAGE "Spanish" + +# default section start +Section + + # delete the installed files + RMDir /r $INSTDIR + + # define the path to which the installer should install + SetOutPath $INSTDIR + + # specify the files to go in the output path + File /r ${SOURCE_FILES} + + # create the uninstaller + WriteUninstaller "$INSTDIR\${FILE_NAME_UNINSTALLER}" + + # create shortcuts in the start menu and on the desktop + CreateDirectory "$SMPROGRAMS\${GROUP_NAME}\${FOLDER_NAME}" + CreateShortCut "$SMPROGRAMS\${GROUP_NAME}\${FOLDER_NAME}\${APP_NAME}.lnk" "$INSTDIR\${FILE_NAME_EXECUTABLE}" + CreateShortCut "$SMPROGRAMS\${GROUP_NAME}\${FOLDER_NAME}\${APP_NAME} (English).lnk" "$INSTDIR\${FILE_NAME_EXECUTABLE}" "--lang=en" + CreateShortCut "$SMPROGRAMS\${GROUP_NAME}\${FOLDER_NAME}\Uninstall ${APP_NAME}.lnk" "$INSTDIR\${FILE_NAME_UNINSTALLER}" + CreateShortCut "$DESKTOP\${APP_NAME}.lnk" "$INSTDIR\${FILE_NAME_EXECUTABLE}" + +SectionEnd + +# create a section to define what the uninstaller does +Section "Uninstall" + + # delete the installed files + RMDir /r $INSTDIR + + # delete the shortcuts + Delete "$SMPROGRAMS\${GROUP_NAME}\${FOLDER_NAME}\${APP_NAME}.lnk" + Delete "$SMPROGRAMS\${GROUP_NAME}\${FOLDER_NAME}\${APP_NAME} (English).lnk" + Delete "$SMPROGRAMS\${GROUP_NAME}\${FOLDER_NAME}\Uninstall ${APP_NAME}.lnk" + RMDir "$SMPROGRAMS\${GROUP_NAME}\${FOLDER_NAME}" + RMDir "$SMPROGRAMS\${GROUP_NAME}" + Delete "$DESKTOP\${APP_NAME}.lnk" + +SectionEnd \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js index cdcfdf9c..73b7c20f 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -9,6 +9,7 @@ var path = require('path'); var archiver = require('archiver'); var del = require('del'); var NwBuilder = require('nw-builder'); +var makensis = require('makensis'); var gulp = require('gulp'); var concat = require('gulp-concat'); @@ -338,7 +339,37 @@ gulp.task('debug', ['dist', 'clean-debug'], function (done) { }); }); -// Create distribution package for windows and linux platforms +// Create installer package for windows platforms +function releaseWin(arch) { + + // Create the output directory, with write permissions + fs.mkdir(releaseDir, '0775', function(err) { + if (err) { + if (err.code !== 'EEXIST') { + throw err; + } + } + }); + + // Parameters passed to the installer script + const options = { + verbose: 2, + define: { + 'VERSION': pkg.version, + 'PLATFORM': arch, + 'DEST_FOLDER': releaseDir + } + } + var output = makensis.compileSync('./assets/windows/installer.nsi', options); + + if (output.status === 0) { + console.log('Installer finished for platform: ' + arch); + } else { + console.error('Installer for platform ' + arch + ' finished with error ' + output.status + ': ' + output.stderr); + } +} + +// Create distribution package (zip) for windows and linux platforms function release(arch) { var src = path.join(appsDir, pkg.name, arch); var output = fs.createWriteStream(path.join(releaseDir, get_release_filename(arch, 'zip'))); @@ -423,11 +454,11 @@ gulp.task('release', ['apps', 'clean-release'], function () { } if (platforms.indexOf('win32') !== -1) { - release('win32'); + releaseWin('win32'); } if (platforms.indexOf('win64') !== -1) { - release('win64'); + releaseWin('win64'); } }); diff --git a/package.json b/package.json index 0ad1e25b..e41ff97f 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,8 @@ "os": "^0.1.1", "platform-dependent-modules": "0.0.14", "run-sequence": "^2.2.0", - "temp": "^0.8.3" + "temp": "^0.8.3", + "makensis": "^0.9.0" }, "config": { "platformDependentModules": {