diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ccbd0db3d..f2f778d62 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -75,6 +75,8 @@ jobs: toolchain: stable - uses: Swatinem/rust-cache@v1 + with: + key: ${{ secrets.CACHE_VERSION }} - uses: davidB/rust-cargo-make@v1 with: @@ -84,10 +86,7 @@ jobs: uses: actions/cache@v2 with: path: ${{ env.PIP_CACHE_DIR }} - key: ${{ runner.os }}-pyproject-toml-${{ hashFiles('pyproject.toml') }} - restore-keys: | - ${{ runner.os }}-pyproject-toml- - ${{ runner.os }}- + key: ${{ runner.os }}-pyproject-toml-${{ secrets.CACHE_VERSION }}-${{ hashFiles('pyproject.toml') }} - name: Set up python builder shell: bash @@ -140,6 +139,8 @@ jobs: components: rustfmt, clippy - uses: Swatinem/rust-cache@v1 + with: + key: ${{ secrets.CACHE_VERSION }} - uses: davidB/rust-cargo-make@v1 with: @@ -153,10 +154,7 @@ jobs: uses: actions/cache@v2 with: path: ${{ env.PIP_CACHE_DIR }} - key: ${{ runner.os }}-pyproject-toml-${{ hashFiles('pyproject.toml') }} - restore-keys: | - ${{ runner.os }}-pyproject-toml- - ${{ runner.os }}- + key: ${{ runner.os }}-pyproject-toml-${{ secrets.CACHE_VERSION }}-${{ hashFiles('pyproject.toml') }} - name: Set up python builder shell: bash @@ -253,6 +251,8 @@ jobs: components: rustfmt, clippy - uses: Swatinem/rust-cache@v1 + with: + key: ${{ secrets.CACHE_VERSION }} - uses: davidB/rust-cargo-make@v1 with: @@ -262,10 +262,7 @@ jobs: uses: actions/cache@v2 with: path: ${{ env.PIP_CACHE_DIR }} - key: ${{ runner.os }}-pyproject-toml-${{ hashFiles('pyproject.toml') }} - restore-keys: | - ${{ runner.os }}-pyproject-toml- - ${{ runner.os }}- + key: ${{ runner.os }}-pyproject-toml-${{ secrets.CACHE_VERSION }}-${{ hashFiles('pyproject.toml') }} - name: Set up python builder shell: bash @@ -287,6 +284,14 @@ jobs: cargo make create-dist if: matrix.os != 'windows-2019' + - name: Create ${{ runner.os }} Installers. + shell: bash + run: | + cargo make dist-to-installer + INSTALLER_ARCHIVE=$(find installers/Windows -maxdepth 1 -iname "*.exe") + echo "INSTALLER_ARCHIVE=$INSTALLER_ARCHIVE" >>$GITHUB_ENV + if: matrix.os == 'windows-2019' && github.event_name == 'push' && contains(github.ref, 'refs/tags') + - name: Pull Git LFS objects run: git lfs pull env: @@ -316,6 +321,12 @@ jobs: path: | ${{ env.RELEASE_ARCHIVE }} release-archive.filename + - uses: actions/upload-artifact@v2 + with: + name: ${{ runner.os }}-installer + path: | + ${{ env.INSTALLER_ARCHIVE }} + if: matrix.os == 'windows-2019' && github.event_name == 'push' && contains(github.ref, 'refs/tags') - uses: actions/upload-artifact@v2 with: name: ${{ runner.os }}-artifacts-debug diff --git a/.gitignore b/.gitignore index 0f2c4d3de..2cc271f22 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ dist/ console_backend/tests/fileout.json get-pip.py .*.sw? +installers/Windows/*.exe diff --git a/Cargo.lock b/Cargo.lock index 1e0cdc6cd..33dc76560 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -340,6 +340,7 @@ version = "0.1.0" dependencies = [ "pyo3 0.14.5", "windows", + "winres", ] [[package]] @@ -2006,6 +2007,15 @@ dependencies = [ "serde_json", ] +[[package]] +name = "toml" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +dependencies = [ + "serde", +] + [[package]] name = "unicode-segmentation" version = "1.8.0" @@ -2240,6 +2250,15 @@ version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bd8f062d8ca5446358159d79a90be12c543b3a965c847c8f3eedf14b321d399" +[[package]] +name = "winres" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b68db261ef59e9e52806f688020631e987592bd83619edccda9c47d42cde4f6c" +dependencies = [ + "toml", +] + [[package]] name = "wyz" version = "0.2.0" diff --git a/Makefile.toml b/Makefile.toml index 225ad95db..034c4c1e0 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -524,6 +524,14 @@ exec --fail-on-error xz -T 0 -e -9 "${output_name}.tar" [tasks.create-dist] run_task = [{ name = ["build-dist", "purge-dist", "compress-dist"] }] +[tasks.dist-to-installer] + +[tasks.dist-to-installer.windows] +script_runner = "@shell" +script = ''' +makensis /V4 .\installers\Windows\Installer.nsi +''' + [tasks.qml-format] dependencies = ["set-qml-files", "set-qml-app"] script_runner = "@shell" diff --git a/entrypoint/Cargo.toml b/entrypoint/Cargo.toml index c6e2f0c9c..30bd32da8 100644 --- a/entrypoint/Cargo.toml +++ b/entrypoint/Cargo.toml @@ -19,3 +19,6 @@ windows = { version = ">=0.24", features = [ "Win32_System_Console", "Win32_Foundation", ] } + +[target.'cfg(target_os = "windows")'.build-dependencies] +winres = "0.1" diff --git a/entrypoint/build.rs b/entrypoint/build.rs index 36583b8e9..1034c2c5e 100644 --- a/entrypoint/build.rs +++ b/entrypoint/build.rs @@ -1,7 +1,18 @@ -fn main() { +#[cfg(target_os = "windows")] +use winres::WindowsResource; +type Result = std::result::Result>; + +fn main() -> Result<()> { #[cfg(target_os = "linux")] { println!("cargo:rustc-link-lib=dylib=crypt"); println!("cargo:rustc-link-arg=-Wl,-rpath,$ORIGIN/lib"); } + #[cfg(target_os = "windows")] + { + WindowsResource::new() + .set_icon("../resources/images/icon.ico") + .compile()?; + } + Ok(()) } diff --git a/installers/Windows/Installer.nsi b/installers/Windows/Installer.nsi new file mode 100644 index 000000000..30b8e9627 --- /dev/null +++ b/installers/Windows/Installer.nsi @@ -0,0 +1,132 @@ +; This file was adapted from: +; https://github.com/mherrmann/fbs/blob/master/fbs/_defaults/src/installer/windows/Installer.nsi +!include MUI2.nsh +!include FileFunc.nsh +!include LogicLib.nsh +!define MUI_ICON "..\..\resources\images\icon.ico" +!define MUI_UNICON "..\..\resources\images\icon.ico" + +!searchparse /file "..\..\console_backend\src\version.txt" `` VER_MAJOR `.` VER_MINOR `.` VER_PATCH_UNFILTERED `` +!searchparse /noerrors "${VER_PATCH_UNFILTERED}" `` VER_PATCH `-` +!define VERSION_ORIGINAL "${VER_MAJOR}.${VER_MINOR}.${VER_PATCH_UNFILTERED}" +!define VERSION "${VER_MAJOR}.${VER_MINOR}.${VER_PATCH}.0" +!define app_name "Swift Navigation Console" +!define app_executable "console.exe" +!define installer_dir "py39-dist" +!define company_name "Swift Navigation" + + + +!define UNINST_KEY \ + "Software\Microsoft\Windows\CurrentVersion\Uninstall\${app_name}" + +VIProductVersion "${VERSION}" +VIAddVersionKey "ProductName" "${app_name}" +VIAddVersionKey "FileVersion" "${VERSION}" +VIAddVersionKey "ProductVersion" "${VERSION}" +VIAddVersionKey "LegalCopyright" "(C) ${company_name}" +VIAddVersionKey "FileDescription" "${app_name}" + +!define MULTIUSER_EXECUTIONLEVEL Standard ; Switch to "Highest" for All Users when available otherwise current user. + +!define MULTIUSER_INSTALLMODE_COMMANDLINE +!include MultiUser.nsh + +;-------------------------------- +;Init + +Function .onInit + !insertmacro MULTIUSER_INIT + ; Do not use InstallDir at all so we can detect empty $InstDir! + ${If} $InstDir == "" ; /D not used + ${If} $MultiUser.InstallMode == "AllUsers" + StrCpy $InstDir "$PROGRAMFILES64\${company_name}\${app_name}" + ${Else} + StrCpy $InstDir "$LOCALAPPDATA\${company_name}\${app_name}" + ${EndIf} + ${EndIf} + +FunctionEnd + +;-------------------------------- +;General + + Name "${app_name}" + OutFile "${app_name}-${VERSION_ORIGINAL}.exe" + +;-------------------------------- +;Interface Settings + + !define MUI_ABORTWARNING + +;-------------------------------- +;Pages + !define MUI_WELCOMEPAGE_TEXT "This wizard will guide you through the installation of ${app_name} version ${VERSION_ORIGINAL}.$\r$\n$\r$\n$\r$\nClick Next to continue." + !insertmacro MUI_PAGE_WELCOME + !insertmacro MUI_PAGE_DIRECTORY + !insertmacro MUI_PAGE_INSTFILES + !define MUI_FINISHPAGE_NOAUTOCLOSE + !define MUI_FINISHPAGE_RUN + !define MUI_FINISHPAGE_RUN_CHECKED + !define MUI_FINISHPAGE_RUN_TEXT "Run ${app_name}" + !define MUI_FINISHPAGE_RUN_FUNCTION "LaunchAsNonAdmin" + !insertmacro MUI_PAGE_FINISH + + !insertmacro MUI_UNPAGE_CONFIRM + !insertmacro MUI_UNPAGE_INSTFILES + +;-------------------------------- +;Languages + + !insertmacro MUI_LANGUAGE "English" + +;-------------------------------- +;Installer Sections + +Section + SetOutPath "$InstDir" + Call Uninstall + File /r "..\..\${installer_dir}\*" + WriteRegStr SHCTX "Software\${app_name}" "" $InstDir + WriteUninstaller "$InstDir\uninstall.exe" + CreateShortCut "$DESKTOP\${app_name}.lnk" "$InstDir\${app_executable}" + CreateShortCut "$SMPROGRAMS\${app_name}.lnk" "$InstDir\${app_executable}" + WriteRegStr SHCTX "${UNINST_KEY}" "DisplayName" "${app_name}" + WriteRegStr SHCTX "${UNINST_KEY}" "UninstallString" \ + "$\"$InstDir\uninstall.exe$\" /$MultiUser.InstallMode" + WriteRegStr SHCTX "${UNINST_KEY}" "QuietUninstallString" \ + "$\"$InstDir\uninstall.exe$\" /$MultiUser.InstallMode /S" + WriteRegStr SHCTX "${UNINST_KEY}" "Publisher" "${company_name}" + WriteRegStr SHCTX "${UNINST_KEY}" "DisplayIcon" "$InstDir\uninstall.exe" + ${GetSize} "$InstDir" "/S=0K" $0 $1 $2 + IntFmt $0 "0x%08X" $0 + WriteRegDWORD SHCTX "${UNINST_KEY}" "EstimatedSize" "$0" + +SectionEnd + +;-------------------------------- +;Uninstaller Section + +Section "Uninstall" + Call un.Uninstall +SectionEnd + +Function LaunchAsNonAdmin + Exec '"$WINDIR\explorer.exe" "$InstDir\${app_executable}"' +FunctionEnd + +!macro Uninstall Prefix +Function ${Prefix}Uninstall + RMDir /r "$InstDir" + Delete "$DESKTOP\${app_name}.lnk" + Delete "$SMPROGRAMS\${app_name}.lnk" + DeleteRegKey /ifempty SHCTX "Software\${app_name}" + DeleteRegKey SHCTX "${UNINST_KEY}" +FunctionEnd +!macroend +!insertmacro Uninstall "" +!insertmacro Uninstall "un." + +Function un.onInit + !insertmacro MULTIUSER_UNINIT +FunctionEnd \ No newline at end of file diff --git a/resources/console_resources.qrc b/resources/console_resources.qrc index 0e6945df1..032027b2c 100644 --- a/resources/console_resources.qrc +++ b/resources/console_resources.qrc @@ -94,6 +94,7 @@ images/fontawesome/file-import.svg images/fontawesome/exclamation-triangle.svg images/icon.png + images/icon.ico TableComponents/SortableColumnHeading.qml TableComponents/TableCellDelegate.qml BaseComponents/SmallCheckBox.qml diff --git a/resources/images/icon.ico b/resources/images/icon.ico new file mode 100644 index 000000000..f84fe21d0 Binary files /dev/null and b/resources/images/icon.ico differ diff --git a/swiftnav_console/main.py b/swiftnav_console/main.py index 1dce49517..b4c3f5615 100644 --- a/swiftnav_console/main.py +++ b/swiftnav_console/main.py @@ -16,7 +16,7 @@ from PySide2 import QtQml, QtCore -from PySide2.QtGui import QFontDatabase +from PySide2.QtGui import QFontDatabase, QIcon from PySide2.QtQml import QQmlComponent, qmlRegisterType @@ -796,6 +796,7 @@ def main(): QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling) QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps) app = QApplication(sys.argv) + app.setWindowIcon(QIcon(":/images/icon.ico")) app.setOrganizationName(ApplicationMetadata.ORGANIZATION_NAME) app.setOrganizationDomain(ApplicationMetadata.ORGANIZATION_DOMAIN) app.setApplicationName(ApplicationMetadata.APPLICATION_NAME)