From e72fee357930f56af4887c9237da8c9584320ca8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Capelle?= Date: Sun, 7 Jul 2024 21:11:48 +0200 Subject: [PATCH 01/12] Move to VCPKG. * Add proper CMake packaging for UIBase. * Install pdb to pdb subfolder instead of lib. * Add alias mo2::uibase target for uibase. * Use spdlog from MO2 registry. * Generate translations for UIBase. * Publish release on tag. * Add a few string methods to remove boost dependencies. --- .github/workflows/build.yml | 89 +++- .gitignore | 2 + CMakeLists.txt | 41 +- CMakePresets.json | 63 +++ README.md | 57 ++- cmake/config.cmake.in | 13 + {src => include/uibase}/delayedfilewriter.h | 0 {src => include/uibase}/diagnosisreport.h | 0 {src => include/uibase}/dllimport.h | 0 {src => include/uibase}/errorcodes.h | 0 {src => include/uibase}/eventfilter.h | 0 {src => include/uibase}/exceptions.h | 0 {src => include/uibase}/executableinfo.h | 0 {src => include/uibase}/expanderwidget.h | 0 {src => include/uibase}/filemapping.h | 0 {src => include/uibase}/filesystemutilities.h | 0 {src => include/uibase}/filterwidget.h | 0 {src => include/uibase}/finddialog.h | 0 {src => include/uibase}/formatters.h | 0 {src => include/uibase}/formatters/enums.h | 0 {src => include/uibase}/formatters/qt.h | 0 .../formatters/random_access_containers.h | 0 {src => include/uibase}/formatters/strings.h | 0 .../uibase}/game_features/bsainvalidation.h | 0 .../uibase}/game_features/dataarchives.h | 0 .../uibase}/game_features/game_feature.h | 0 .../uibase}/game_features/gameplugins.h | 0 .../uibase}/game_features/igamefeatures.h | 0 .../uibase}/game_features/localsavegames.h | 2 +- .../uibase}/game_features/moddatachecker.h | 0 .../uibase}/game_features/moddatacontent.h | 0 .../uibase}/game_features/savegameinfo.h | 0 .../uibase}/game_features/scriptextender.h | 0 .../uibase}/game_features/unmanagedmods.h | 0 {src => include/uibase}/guessedvalue.h | 0 {src => include/uibase}/idownloadmanager.h | 0 {src => include/uibase}/ifiletree.h | 0 .../uibase}/iinstallationmanager.h | 0 {src => include/uibase}/imodinterface.h | 0 {src => include/uibase}/imodlist.h | 0 .../uibase}/imodrepositorybridge.h | 0 {src => include/uibase}/imoinfo.h | 2 +- {src => include/uibase}/iplugin.h | 0 {src => include/uibase}/iplugindiagnose.h | 0 {src => include/uibase}/ipluginfilemapper.h | 0 {src => include/uibase}/iplugingame.h | 0 {src => include/uibase}/iplugingamefeatures.h | 0 {src => include/uibase}/iplugininstaller.h | 0 .../uibase}/iplugininstallercustom.h | 0 .../uibase}/iplugininstallersimple.h | 0 {src => include/uibase}/ipluginlist.h | 0 {src => include/uibase}/ipluginmodpage.h | 0 {src => include/uibase}/ipluginpreview.h | 0 {src => include/uibase}/ipluginproxy.h | 0 {src => include/uibase}/iplugintool.h | 0 {src => include/uibase}/iprofile.h | 0 {src => include/uibase}/isavegame.h | 0 {src => include/uibase}/isavegameinfowidget.h | 0 {src => include/uibase}/json.h | 0 {src => include/uibase}/lineeditclear.h | 0 {src => include/uibase}/linklabel.h | 0 {src => include/uibase}/log.h | 4 +- {src => include/uibase}/memoizedlock.h | 0 {src => include/uibase}/moassert.h | 0 .../uibase}/modrepositoryfileinfo.h | 0 {src => include/uibase}/nxmurl.h | 0 {src => include/uibase}/pluginrequirements.h | 0 {src => include/uibase}/pluginsetting.h | 0 {src => include/uibase}/questionboxmemory.h | 0 {src => include/uibase}/registry.h | 0 {src => include/uibase}/report.h | 0 {src => include/uibase}/safewritefile.h | 0 {src => include/uibase}/scopeguard.h | 0 {src => include/uibase}/sortabletreewidget.h | 0 {src => include/uibase}/steamutility.h | 0 include/uibase/strings.h | 16 + {src => include/uibase}/taskprogressmanager.h | 0 {src => include/uibase}/textviewer.h | 0 {src => include/uibase}/tutorabledialog.h | 0 {src => include/uibase}/tutorialcontrol.h | 0 {src => include/uibase}/tutorialmanager.h | 0 {src => include/uibase}/utility.h | 0 {src => include/uibase}/versioninfo.h | 0 {src => include/uibase}/widgetutility.h | 0 src/CMakeLists.txt | 258 ++++++++--- src/SConscript | 52 --- src/log.cpp | 17 +- src/strings.cpp | 46 ++ src/uibase_en.ts | 407 ++++++++++++++++++ src/version.rc | 6 +- tests/CMakeLists.txt | 10 +- tests/cmake/CMakeLists.txt | 9 + tests/cmake/plugin.cpp | 4 + tests/test_formatters.cpp | 2 +- tests/test_ifiletree.cpp | 2 +- tests/test_strings.cpp | 33 ++ vcpkg-configuration.json | 21 + vcpkg.json | 15 + 98 files changed, 1016 insertions(+), 155 deletions(-) create mode 100644 CMakePresets.json create mode 100644 cmake/config.cmake.in rename {src => include/uibase}/delayedfilewriter.h (100%) rename {src => include/uibase}/diagnosisreport.h (100%) rename {src => include/uibase}/dllimport.h (100%) rename {src => include/uibase}/errorcodes.h (100%) rename {src => include/uibase}/eventfilter.h (100%) rename {src => include/uibase}/exceptions.h (100%) rename {src => include/uibase}/executableinfo.h (100%) rename {src => include/uibase}/expanderwidget.h (100%) rename {src => include/uibase}/filemapping.h (100%) rename {src => include/uibase}/filesystemutilities.h (100%) rename {src => include/uibase}/filterwidget.h (100%) rename {src => include/uibase}/finddialog.h (100%) rename {src => include/uibase}/formatters.h (100%) rename {src => include/uibase}/formatters/enums.h (100%) rename {src => include/uibase}/formatters/qt.h (100%) rename {src => include/uibase}/formatters/random_access_containers.h (100%) rename {src => include/uibase}/formatters/strings.h (100%) rename {src => include/uibase}/game_features/bsainvalidation.h (100%) rename {src => include/uibase}/game_features/dataarchives.h (100%) rename {src => include/uibase}/game_features/game_feature.h (100%) rename {src => include/uibase}/game_features/gameplugins.h (100%) rename {src => include/uibase}/game_features/igamefeatures.h (100%) rename {src => include/uibase}/game_features/localsavegames.h (94%) rename {src => include/uibase}/game_features/moddatachecker.h (100%) rename {src => include/uibase}/game_features/moddatacontent.h (100%) rename {src => include/uibase}/game_features/savegameinfo.h (100%) rename {src => include/uibase}/game_features/scriptextender.h (100%) rename {src => include/uibase}/game_features/unmanagedmods.h (100%) rename {src => include/uibase}/guessedvalue.h (100%) rename {src => include/uibase}/idownloadmanager.h (100%) rename {src => include/uibase}/ifiletree.h (100%) rename {src => include/uibase}/iinstallationmanager.h (100%) rename {src => include/uibase}/imodinterface.h (100%) rename {src => include/uibase}/imodlist.h (100%) rename {src => include/uibase}/imodrepositorybridge.h (100%) rename {src => include/uibase}/imoinfo.h (99%) rename {src => include/uibase}/iplugin.h (100%) rename {src => include/uibase}/iplugindiagnose.h (100%) rename {src => include/uibase}/ipluginfilemapper.h (100%) rename {src => include/uibase}/iplugingame.h (100%) rename {src => include/uibase}/iplugingamefeatures.h (100%) rename {src => include/uibase}/iplugininstaller.h (100%) rename {src => include/uibase}/iplugininstallercustom.h (100%) rename {src => include/uibase}/iplugininstallersimple.h (100%) rename {src => include/uibase}/ipluginlist.h (100%) rename {src => include/uibase}/ipluginmodpage.h (100%) rename {src => include/uibase}/ipluginpreview.h (100%) rename {src => include/uibase}/ipluginproxy.h (100%) rename {src => include/uibase}/iplugintool.h (100%) rename {src => include/uibase}/iprofile.h (100%) rename {src => include/uibase}/isavegame.h (100%) rename {src => include/uibase}/isavegameinfowidget.h (100%) rename {src => include/uibase}/json.h (100%) rename {src => include/uibase}/lineeditclear.h (100%) rename {src => include/uibase}/linklabel.h (100%) rename {src => include/uibase}/log.h (98%) rename {src => include/uibase}/memoizedlock.h (100%) rename {src => include/uibase}/moassert.h (100%) rename {src => include/uibase}/modrepositoryfileinfo.h (100%) rename {src => include/uibase}/nxmurl.h (100%) rename {src => include/uibase}/pluginrequirements.h (100%) rename {src => include/uibase}/pluginsetting.h (100%) rename {src => include/uibase}/questionboxmemory.h (100%) rename {src => include/uibase}/registry.h (100%) rename {src => include/uibase}/report.h (100%) rename {src => include/uibase}/safewritefile.h (100%) rename {src => include/uibase}/scopeguard.h (100%) rename {src => include/uibase}/sortabletreewidget.h (100%) rename {src => include/uibase}/steamutility.h (100%) create mode 100644 include/uibase/strings.h rename {src => include/uibase}/taskprogressmanager.h (100%) rename {src => include/uibase}/textviewer.h (100%) rename {src => include/uibase}/tutorabledialog.h (100%) rename {src => include/uibase}/tutorialcontrol.h (100%) rename {src => include/uibase}/tutorialmanager.h (100%) rename {src => include/uibase}/utility.h (100%) rename {src => include/uibase}/versioninfo.h (100%) rename {src => include/uibase}/widgetutility.h (100%) delete mode 100644 src/SConscript create mode 100644 src/strings.cpp create mode 100644 src/uibase_en.ts create mode 100644 tests/cmake/CMakeLists.txt create mode 100644 tests/cmake/plugin.cpp create mode 100644 tests/test_strings.cpp create mode 100644 vcpkg-configuration.json create mode 100644 vcpkg.json diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 27b73f02..893fa507 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,25 +3,92 @@ name: Build UIBase on: push: branches: master + tags: + - "*" pull_request: types: [opened, synchronize, reopened] +env: + VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite" + jobs: build: runs-on: windows-2022 steps: - - name: Build UI Base - id: build-uibase - uses: ModOrganizer2/build-with-mob-action@master + # https://learn.microsoft.com/en-us/vcpkg/consume/binary-caching-github-actions-cache + - name: Export GitHub Actions cache environment variables + uses: actions/github-script@v7 with: - mo2-third-parties: gtest spdlog boost - mo2-dependencies: cmake_common - mo2-cmake-command: -DUIBASE_TESTS=1 .. + script: | + core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); + core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + + - name: Install Qt + uses: jurplel/install-qt-action@v3 + with: + version: 6.7.0 + modules: + cache: true + + - uses: actions/checkout@v4 + - uses: lukka/run-vcpkg@v11 - - name: Build UI Base Tests - run: cmake --build vsbuild --config RelWithDebInfo -j4 --target uibase-tests - working-directory: ${{ steps.build-uibase.outputs.working-directory }} + - name: Configure UI Base build + shell: pwsh + run: | + cmake --preset vs2022-windows ` + "-DCMAKE_PREFIX_PATH=${env:QT_ROOT_DIR}\msvc2019_64" ` + "-DCMAKE_INSTALL_PREFIX=install" -DUIBASE_TESTING=ON + + # build both Debug and RelWithDebInfo for package + - name: Build UI Base + run: | + cmake --build vsbuild --config Debug --target uibase-tests --verbose + cmake --build vsbuild --config RelWithDebInfo --target uibase-tests --verbose - name: Test UI Base - run: ctest --test-dir vsbuild -C RelWithDebInfo --output-on-failure - working-directory: ${{ steps.build-uibase.outputs.working-directory }} + run: | + ctest --test-dir vsbuild -C Debug --output-on-failure + ctest --test-dir vsbuild -C RelWithDebInfo --output-on-failure + + - name: Install UI Base + run: | + cmake --install vsbuild --config Debug + cmake --install vsbuild --config RelWithDebInfo + + # this tests that UI Base can be properly used as a CMake package + - name: Test UI Base package + run: | + cmake -B build . "-DCMAKE_PREFIX_PATH=${env:QT_ROOT_DIR}\msvc2019_64;..\..\install\lib\cmake\" + cmake --build build --config Debug + cmake --build build --config Release + cmake --build build --config RelWithDebInfo + working-directory: tests/cmake + + - name: Upload UI Base artifact + uses: actions/upload-artifact@master + with: + name: uibase + path: ./install + + publish: + if: github.ref_type == 'tag' + needs: build + runs-on: windows-2022 + permissions: + contents: write + steps: + - name: Download Artifact + uses: actions/download-artifact@master + with: + name: uibase + path: ./install + + - name: Create UI Base archive + run: 7z a uibase_${{ github.ref_name }}.7z ./install/* + + - name: Publish Release + env: + GH_TOKEN: ${{ github.token }} + GH_REPO: ${{ github.repository }} + run: gh release create --draft=false --notes="${{ github.ref_name }}" "${{ github.ref_name }}" ./uibase_${{ github.ref_name }}.7z diff --git a/.gitignore b/.gitignore index 1dfac70c..bcdbd6a5 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ CMakeLists.txt.user /*std*.log /*build /src/uibasetests_en.ts +/install +/tests/cmake/build diff --git a/CMakeLists.txt b/CMakeLists.txt index 800fa66d..ec4792c4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,17 +1,44 @@ cmake_minimum_required(VERSION 3.16) +include(CMakePackageConfigHelpers) + project(uibase) -if(DEFINED DEPENDENCIES_DIR) - include(${DEPENDENCIES_DIR}/modorganizer_super/cmake_common/mo2.cmake) -else() - include(${CMAKE_CURRENT_LIST_DIR}/../cmake_common/mo2.cmake) -endif() +find_package(mo2-cmake CONFIG REQUIRED) add_subdirectory(src) -set(UIBASE_TESTS ${UIBASE_TESTS} CACHE BOOL "build tests for uibase") -if (UIBASE_TESTS) +mo2_set_project_to_run_from_install(uibase EXECUTABLE ${CMAKE_INSTALL_PREFIX}/bin/ModOrganizer.exe) +set_property(DIRECTORY ${PROJECT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT uibase) + +configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/config.cmake.in + "${CMAKE_CURRENT_BINARY_DIR}/mo2-uibase-config.cmake" + INSTALL_DESTINATION "lib/cmake/mo2-uibase" + NO_SET_AND_CHECK_MACRO + NO_CHECK_REQUIRED_COMPONENTS_MACRO +) + +file(READ "${CMAKE_CURRENT_SOURCE_DIR}/src/version.rc" uibase_version) +string(REGEX MATCH "#define VER_FILEVERSION\\s*([0-9]+),([0-9]+),([0-9]+)" _ ${uibase_version}) +set(uibase_version_major ${CMAKE_MATCH_1}) +set(uibase_version_minor ${CMAKE_MATCH_2}) +set(uibase_version_patch ${CMAKE_MATCH_3}) + +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/mo2-uibase-config-version.cmake" + VERSION "${uibase_version_major}.${uibase_version_minor}.${uibase_version_patch}" + COMPATIBILITY AnyNewerVersion + ARCH_INDEPENDENT +) + +install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/mo2-uibase-config.cmake + ${CMAKE_CURRENT_BINARY_DIR}/mo2-uibase-config-version.cmake + DESTINATION lib/cmake/mo2-uibase +) + +set(UIBASE_TESTING ${UIBASE_TESTING} CACHE BOOL "build tests for uibase") +if (UIBASE_TESTING) enable_testing() add_subdirectory(tests) endif() diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 00000000..0c06d1a3 --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,63 @@ +{ + "configurePresets": [ + { + "errors": { + "deprecated": true + }, + "hidden": true, + "name": "cmake-dev", + "warnings": { + "deprecated": true, + "dev": true + } + }, + { + "cacheVariables": { + "VCPKG_MANIFEST_NO_DEFAULT_FEATURES": { + "type": "BOOL", + "value": "ON" + } + }, + "toolchainFile": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", + "hidden": true, + "name": "vcpkg" + }, + { + "cacheVariables": { + "VCPKG_MANIFEST_FEATURES": { + "type": "STRING", + "value": "testing" + } + }, + "hidden": true, + "inherits": ["vcpkg"], + "name": "vcpkg-dev" + }, + { + "binaryDir": "${sourceDir}/vsbuild", + "architecture": { + "strategy": "set", + "value": "x64" + }, + "cacheVariables": { + "CMAKE_CXX_FLAGS": "/EHsc /MP /W4", + "VCPKG_TARGET_TRIPLET": { + "type": "STRING", + "value": "x64-windows-static-md" + } + }, + "generator": "Visual Studio 17 2022", + "inherits": ["cmake-dev", "vcpkg-dev"], + "name": "vs2022-windows", + "toolset": "v143" + } + ], + "buildPresets": [ + { + "name": "vs2022-windows", + "resolvePackageReferences": "on", + "configurePreset": "vs2022-windows" + } + ], + "version": 4 +} diff --git a/README.md b/README.md index 97468b30..ba220be2 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,56 @@ -[![Build status](https://ci.appveyor.com/api/projects/status/g8c6tujn0pne6tsk?svg=true)](https://ci.appveyor.com/project/Modorganizer2/modorganizer-uibase) - # modorganizer-uibase + +[![Build status](https://github.com/ModOrganizer2/modorganizer-uibase/actions/workflows/build.yml/badge.svg?branch=dev/vcpkg)](https://github.com/ModOrganizer2/modorganizer-uibase/actions) +[![Lint status]](https://github.com/ModOrganizer2/modorganizer-uibase/actions/workflows/linting.yml/badge.svg?branch=dev/vcpkg)]() + +## How to build? + +```pwsh +# set to the appropriate path for Qt +$env:QT_ROOT = "C:\Qt\6.7.0\msvc2019_64" + +# set to the appropriate path for VCPKG +$env:VCPKG_ROOT = "C:\vcpkg" + +cmake --preset vs2022-windows "-DCMAKE_PREFIX_PATH=$env:QT_ROOT" ` + -DCMAKE_INSTALL_PREFIX=install ` + -DUIBASE_TESTING=ON + +# build uibase +cmake --build vsbuild --config RelWithDebInfo + +# install uibase +cmake --install vsbuild --config RelWithDebInfo + +# test uibase +ctest --test-dir vsbuild -C RelWithDebInfo --output-on-failure +``` + +Check [`CMakePresets.json`](CMakePresets.json) for some predefined values. Extra options +include: + +- `UIBASE_TESTING` - if specified, build tests for UIBase, requires the VCPKG `testing` + feature to be enabled (enabled in the preset). + +## How to use? + +### As a VCPKG dependency + +**Not implemented yet.** + +### As a CMake target + +Once the CMake targets for `uibase` are generated (see _How to build?_), you can include +`mo2::uibase` in your project: + +1. Add `install/lib` to your `CMAKE_PREFIX_PATH` (replace `install` by the install + location specified during build). +2. Use `uibase` in your `CMakeLists.txt`: + +```cmake +find_package(mo2-uibase CONFIG REQUIRED) + +add_library(myplugin SHARED) + +target_link_libraries(myplugin PRIVATE mo2::uibase) +``` diff --git a/cmake/config.cmake.in b/cmake/config.cmake.in new file mode 100644 index 00000000..d6d78995 --- /dev/null +++ b/cmake/config.cmake.in @@ -0,0 +1,13 @@ +@PACKAGE_INIT@ + +set(_UIBASE_PREFIX_DIR ${PACKAGE_PREFIX_DIR}) + +find_package(Qt6 CONFIG REQUIRED COMPONENTS Network QuickWidgets Widgets) + +include ( "${CMAKE_CURRENT_LIST_DIR}/mo2-uibase-targets.cmake" ) + + +if (MO2_CMAKE_DEPRECATED_UIBASE_INCLUDE) + target_include_directories(mo2::uibase INTERFACE + ${_UIBASE_PREFIX_DIR}/include/uibase ${_UIBASE_PREFIX_DIR}/include/uibase/game_features) +endif() diff --git a/src/delayedfilewriter.h b/include/uibase/delayedfilewriter.h similarity index 100% rename from src/delayedfilewriter.h rename to include/uibase/delayedfilewriter.h diff --git a/src/diagnosisreport.h b/include/uibase/diagnosisreport.h similarity index 100% rename from src/diagnosisreport.h rename to include/uibase/diagnosisreport.h diff --git a/src/dllimport.h b/include/uibase/dllimport.h similarity index 100% rename from src/dllimport.h rename to include/uibase/dllimport.h diff --git a/src/errorcodes.h b/include/uibase/errorcodes.h similarity index 100% rename from src/errorcodes.h rename to include/uibase/errorcodes.h diff --git a/src/eventfilter.h b/include/uibase/eventfilter.h similarity index 100% rename from src/eventfilter.h rename to include/uibase/eventfilter.h diff --git a/src/exceptions.h b/include/uibase/exceptions.h similarity index 100% rename from src/exceptions.h rename to include/uibase/exceptions.h diff --git a/src/executableinfo.h b/include/uibase/executableinfo.h similarity index 100% rename from src/executableinfo.h rename to include/uibase/executableinfo.h diff --git a/src/expanderwidget.h b/include/uibase/expanderwidget.h similarity index 100% rename from src/expanderwidget.h rename to include/uibase/expanderwidget.h diff --git a/src/filemapping.h b/include/uibase/filemapping.h similarity index 100% rename from src/filemapping.h rename to include/uibase/filemapping.h diff --git a/src/filesystemutilities.h b/include/uibase/filesystemutilities.h similarity index 100% rename from src/filesystemutilities.h rename to include/uibase/filesystemutilities.h diff --git a/src/filterwidget.h b/include/uibase/filterwidget.h similarity index 100% rename from src/filterwidget.h rename to include/uibase/filterwidget.h diff --git a/src/finddialog.h b/include/uibase/finddialog.h similarity index 100% rename from src/finddialog.h rename to include/uibase/finddialog.h diff --git a/src/formatters.h b/include/uibase/formatters.h similarity index 100% rename from src/formatters.h rename to include/uibase/formatters.h diff --git a/src/formatters/enums.h b/include/uibase/formatters/enums.h similarity index 100% rename from src/formatters/enums.h rename to include/uibase/formatters/enums.h diff --git a/src/formatters/qt.h b/include/uibase/formatters/qt.h similarity index 100% rename from src/formatters/qt.h rename to include/uibase/formatters/qt.h diff --git a/src/formatters/random_access_containers.h b/include/uibase/formatters/random_access_containers.h similarity index 100% rename from src/formatters/random_access_containers.h rename to include/uibase/formatters/random_access_containers.h diff --git a/src/formatters/strings.h b/include/uibase/formatters/strings.h similarity index 100% rename from src/formatters/strings.h rename to include/uibase/formatters/strings.h diff --git a/src/game_features/bsainvalidation.h b/include/uibase/game_features/bsainvalidation.h similarity index 100% rename from src/game_features/bsainvalidation.h rename to include/uibase/game_features/bsainvalidation.h diff --git a/src/game_features/dataarchives.h b/include/uibase/game_features/dataarchives.h similarity index 100% rename from src/game_features/dataarchives.h rename to include/uibase/game_features/dataarchives.h diff --git a/src/game_features/game_feature.h b/include/uibase/game_features/game_feature.h similarity index 100% rename from src/game_features/game_feature.h rename to include/uibase/game_features/game_feature.h diff --git a/src/game_features/gameplugins.h b/include/uibase/game_features/gameplugins.h similarity index 100% rename from src/game_features/gameplugins.h rename to include/uibase/game_features/gameplugins.h diff --git a/src/game_features/igamefeatures.h b/include/uibase/game_features/igamefeatures.h similarity index 100% rename from src/game_features/igamefeatures.h rename to include/uibase/game_features/igamefeatures.h diff --git a/src/game_features/localsavegames.h b/include/uibase/game_features/localsavegames.h similarity index 94% rename from src/game_features/localsavegames.h rename to include/uibase/game_features/localsavegames.h index 2db6a4e2..f425431e 100644 --- a/src/game_features/localsavegames.h +++ b/include/uibase/game_features/localsavegames.h @@ -3,8 +3,8 @@ #include +#include "../filemapping.h" #include "./game_feature.h" -#include "filemapping.h" namespace MOBase { diff --git a/src/game_features/moddatachecker.h b/include/uibase/game_features/moddatachecker.h similarity index 100% rename from src/game_features/moddatachecker.h rename to include/uibase/game_features/moddatachecker.h diff --git a/src/game_features/moddatacontent.h b/include/uibase/game_features/moddatacontent.h similarity index 100% rename from src/game_features/moddatacontent.h rename to include/uibase/game_features/moddatacontent.h diff --git a/src/game_features/savegameinfo.h b/include/uibase/game_features/savegameinfo.h similarity index 100% rename from src/game_features/savegameinfo.h rename to include/uibase/game_features/savegameinfo.h diff --git a/src/game_features/scriptextender.h b/include/uibase/game_features/scriptextender.h similarity index 100% rename from src/game_features/scriptextender.h rename to include/uibase/game_features/scriptextender.h diff --git a/src/game_features/unmanagedmods.h b/include/uibase/game_features/unmanagedmods.h similarity index 100% rename from src/game_features/unmanagedmods.h rename to include/uibase/game_features/unmanagedmods.h diff --git a/src/guessedvalue.h b/include/uibase/guessedvalue.h similarity index 100% rename from src/guessedvalue.h rename to include/uibase/guessedvalue.h diff --git a/src/idownloadmanager.h b/include/uibase/idownloadmanager.h similarity index 100% rename from src/idownloadmanager.h rename to include/uibase/idownloadmanager.h diff --git a/src/ifiletree.h b/include/uibase/ifiletree.h similarity index 100% rename from src/ifiletree.h rename to include/uibase/ifiletree.h diff --git a/src/iinstallationmanager.h b/include/uibase/iinstallationmanager.h similarity index 100% rename from src/iinstallationmanager.h rename to include/uibase/iinstallationmanager.h diff --git a/src/imodinterface.h b/include/uibase/imodinterface.h similarity index 100% rename from src/imodinterface.h rename to include/uibase/imodinterface.h diff --git a/src/imodlist.h b/include/uibase/imodlist.h similarity index 100% rename from src/imodlist.h rename to include/uibase/imodlist.h diff --git a/src/imodrepositorybridge.h b/include/uibase/imodrepositorybridge.h similarity index 100% rename from src/imodrepositorybridge.h rename to include/uibase/imodrepositorybridge.h diff --git a/src/imoinfo.h b/include/uibase/imoinfo.h similarity index 99% rename from src/imoinfo.h rename to include/uibase/imoinfo.h index 407a379a..e4f072a8 100644 --- a/src/imoinfo.h +++ b/include/uibase/imoinfo.h @@ -30,7 +30,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include #include -#include "game_feature.h" +#include "game_features/game_feature.h" #include "guessedvalue.h" #include "imodlist.h" #include "iprofile.h" diff --git a/src/iplugin.h b/include/uibase/iplugin.h similarity index 100% rename from src/iplugin.h rename to include/uibase/iplugin.h diff --git a/src/iplugindiagnose.h b/include/uibase/iplugindiagnose.h similarity index 100% rename from src/iplugindiagnose.h rename to include/uibase/iplugindiagnose.h diff --git a/src/ipluginfilemapper.h b/include/uibase/ipluginfilemapper.h similarity index 100% rename from src/ipluginfilemapper.h rename to include/uibase/ipluginfilemapper.h diff --git a/src/iplugingame.h b/include/uibase/iplugingame.h similarity index 100% rename from src/iplugingame.h rename to include/uibase/iplugingame.h diff --git a/src/iplugingamefeatures.h b/include/uibase/iplugingamefeatures.h similarity index 100% rename from src/iplugingamefeatures.h rename to include/uibase/iplugingamefeatures.h diff --git a/src/iplugininstaller.h b/include/uibase/iplugininstaller.h similarity index 100% rename from src/iplugininstaller.h rename to include/uibase/iplugininstaller.h diff --git a/src/iplugininstallercustom.h b/include/uibase/iplugininstallercustom.h similarity index 100% rename from src/iplugininstallercustom.h rename to include/uibase/iplugininstallercustom.h diff --git a/src/iplugininstallersimple.h b/include/uibase/iplugininstallersimple.h similarity index 100% rename from src/iplugininstallersimple.h rename to include/uibase/iplugininstallersimple.h diff --git a/src/ipluginlist.h b/include/uibase/ipluginlist.h similarity index 100% rename from src/ipluginlist.h rename to include/uibase/ipluginlist.h diff --git a/src/ipluginmodpage.h b/include/uibase/ipluginmodpage.h similarity index 100% rename from src/ipluginmodpage.h rename to include/uibase/ipluginmodpage.h diff --git a/src/ipluginpreview.h b/include/uibase/ipluginpreview.h similarity index 100% rename from src/ipluginpreview.h rename to include/uibase/ipluginpreview.h diff --git a/src/ipluginproxy.h b/include/uibase/ipluginproxy.h similarity index 100% rename from src/ipluginproxy.h rename to include/uibase/ipluginproxy.h diff --git a/src/iplugintool.h b/include/uibase/iplugintool.h similarity index 100% rename from src/iplugintool.h rename to include/uibase/iplugintool.h diff --git a/src/iprofile.h b/include/uibase/iprofile.h similarity index 100% rename from src/iprofile.h rename to include/uibase/iprofile.h diff --git a/src/isavegame.h b/include/uibase/isavegame.h similarity index 100% rename from src/isavegame.h rename to include/uibase/isavegame.h diff --git a/src/isavegameinfowidget.h b/include/uibase/isavegameinfowidget.h similarity index 100% rename from src/isavegameinfowidget.h rename to include/uibase/isavegameinfowidget.h diff --git a/src/json.h b/include/uibase/json.h similarity index 100% rename from src/json.h rename to include/uibase/json.h diff --git a/src/lineeditclear.h b/include/uibase/lineeditclear.h similarity index 100% rename from src/lineeditclear.h rename to include/uibase/lineeditclear.h diff --git a/src/linklabel.h b/include/uibase/linklabel.h similarity index 100% rename from src/linklabel.h rename to include/uibase/linklabel.h diff --git a/src/log.h b/include/uibase/log.h similarity index 98% rename from src/log.h rename to include/uibase/log.h index d92ef4dd..460c6a52 100644 --- a/src/log.h +++ b/include/uibase/log.h @@ -16,6 +16,7 @@ #include "dllimport.h" #include "formatters.h" +#include "strings.h" namespace spdlog { @@ -62,9 +63,6 @@ concept RuntimeFormatString = requires(F&& f, Args&&... args) { void QDLLEXPORT doLogImpl(spdlog::logger& lg, Levels lv, const std::string& s) noexcept; -void QDLLEXPORT ireplace_all(std::string& input, std::string const& search, - std::string const& replace) noexcept; - template void doLog(spdlog::logger& logger, Levels lv, const std::vector bl, diff --git a/src/memoizedlock.h b/include/uibase/memoizedlock.h similarity index 100% rename from src/memoizedlock.h rename to include/uibase/memoizedlock.h diff --git a/src/moassert.h b/include/uibase/moassert.h similarity index 100% rename from src/moassert.h rename to include/uibase/moassert.h diff --git a/src/modrepositoryfileinfo.h b/include/uibase/modrepositoryfileinfo.h similarity index 100% rename from src/modrepositoryfileinfo.h rename to include/uibase/modrepositoryfileinfo.h diff --git a/src/nxmurl.h b/include/uibase/nxmurl.h similarity index 100% rename from src/nxmurl.h rename to include/uibase/nxmurl.h diff --git a/src/pluginrequirements.h b/include/uibase/pluginrequirements.h similarity index 100% rename from src/pluginrequirements.h rename to include/uibase/pluginrequirements.h diff --git a/src/pluginsetting.h b/include/uibase/pluginsetting.h similarity index 100% rename from src/pluginsetting.h rename to include/uibase/pluginsetting.h diff --git a/src/questionboxmemory.h b/include/uibase/questionboxmemory.h similarity index 100% rename from src/questionboxmemory.h rename to include/uibase/questionboxmemory.h diff --git a/src/registry.h b/include/uibase/registry.h similarity index 100% rename from src/registry.h rename to include/uibase/registry.h diff --git a/src/report.h b/include/uibase/report.h similarity index 100% rename from src/report.h rename to include/uibase/report.h diff --git a/src/safewritefile.h b/include/uibase/safewritefile.h similarity index 100% rename from src/safewritefile.h rename to include/uibase/safewritefile.h diff --git a/src/scopeguard.h b/include/uibase/scopeguard.h similarity index 100% rename from src/scopeguard.h rename to include/uibase/scopeguard.h diff --git a/src/sortabletreewidget.h b/include/uibase/sortabletreewidget.h similarity index 100% rename from src/sortabletreewidget.h rename to include/uibase/sortabletreewidget.h diff --git a/src/steamutility.h b/include/uibase/steamutility.h similarity index 100% rename from src/steamutility.h rename to include/uibase/steamutility.h diff --git a/include/uibase/strings.h b/include/uibase/strings.h new file mode 100644 index 00000000..e0d76a33 --- /dev/null +++ b/include/uibase/strings.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +#include "dllimport.h" + +namespace MOBase +{ + +QDLLEXPORT void ireplace_all(std::string& input, std::string_view search, + std::string_view replace) noexcept; + +QDLLEXPORT bool iequals(std::string_view lhs, std::string_view rhs); + +} // namespace MOBase diff --git a/src/taskprogressmanager.h b/include/uibase/taskprogressmanager.h similarity index 100% rename from src/taskprogressmanager.h rename to include/uibase/taskprogressmanager.h diff --git a/src/textviewer.h b/include/uibase/textviewer.h similarity index 100% rename from src/textviewer.h rename to include/uibase/textviewer.h diff --git a/src/tutorabledialog.h b/include/uibase/tutorabledialog.h similarity index 100% rename from src/tutorabledialog.h rename to include/uibase/tutorabledialog.h diff --git a/src/tutorialcontrol.h b/include/uibase/tutorialcontrol.h similarity index 100% rename from src/tutorialcontrol.h rename to include/uibase/tutorialcontrol.h diff --git a/src/tutorialmanager.h b/include/uibase/tutorialmanager.h similarity index 100% rename from src/tutorialmanager.h rename to include/uibase/tutorialmanager.h diff --git a/src/utility.h b/include/uibase/utility.h similarity index 100% rename from src/utility.h rename to include/uibase/utility.h diff --git a/src/versioninfo.h b/include/uibase/versioninfo.h similarity index 100% rename from src/versioninfo.h rename to include/uibase/versioninfo.h diff --git a/src/widgetutility.h b/include/uibase/widgetutility.h similarity index 100% rename from src/widgetutility.h rename to include/uibase/widgetutility.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6384912a..5b096a67 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,72 +1,214 @@ cmake_minimum_required(VERSION 3.16) +find_package(Qt6 CONFIG REQUIRED COMPONENTS Network Qml Quick QuickWidgets Widgets) +find_package(spdlog CONFIG REQUIRED) + +set(root_headers + ../include/uibase/delayedfilewriter.h + ../include/uibase/diagnosisreport.h + ../include/uibase/dllimport.h + ../include/uibase/errorcodes.h + ../include/uibase/eventfilter.h + ../include/uibase/exceptions.h + ../include/uibase/executableinfo.h + ../include/uibase/filemapping.h + ../include/uibase/filesystemutilities.h + ../include/uibase/guessedvalue.h + ../include/uibase/idownloadmanager.h + ../include/uibase/json.h + ../include/uibase/log.h + ../include/uibase/memoizedlock.h + ../include/uibase/moassert.h + ../include/uibase/modrepositoryfileinfo.h + ../include/uibase/nxmurl.h + ../include/uibase/pluginrequirements.h + ../include/uibase/pluginsetting.h + ../include/uibase/registry.h + ../include/uibase/report.h + ../include/uibase/safewritefile.h + ../include/uibase/scopeguard.h + ../include/uibase/steamutility.h + ../include/uibase/strings.h + ../include/uibase/utility.h + ../include/uibase/versioninfo.h +) +set(interface_headers + ../include/uibase/ifiletree.h + ../include/uibase/iinstallationmanager.h + ../include/uibase/imodinterface.h + ../include/uibase/imodlist.h + ../include/uibase/imodrepositorybridge.h + ../include/uibase/imoinfo.h + ../include/uibase/iplugin.h + ../include/uibase/iplugindiagnose.h + ../include/uibase/ipluginfilemapper.h + ../include/uibase/iplugingame.h + ../include/uibase/iplugingamefeatures.h + ../include/uibase/iplugininstaller.h + ../include/uibase/iplugininstallercustom.h + ../include/uibase/iplugininstallersimple.h + ../include/uibase/ipluginlist.h + ../include/uibase/ipluginmodpage.h + ../include/uibase/ipluginpreview.h + ../include/uibase/ipluginproxy.h + ../include/uibase/iplugintool.h + ../include/uibase/iprofile.h + ../include/uibase/isavegame.h + ../include/uibase/isavegameinfowidget.h +) +set(tutorial_headers + ../include/uibase/tutorabledialog.h + ../include/uibase/tutorialcontrol.h + ../include/uibase/tutorialmanager.h +) +set(widget_headers + ../include/uibase/expanderwidget.h + ../include/uibase/filterwidget.h + ../include/uibase/finddialog.h + ../include/uibase/lineeditclear.h + ../include/uibase/linklabel.h + ../include/uibase/questionboxmemory.h + ../include/uibase/sortabletreewidget.h + ../include/uibase/taskprogressmanager.h + ../include/uibase/textviewer.h + ../include/uibase/widgetutility.h +) +set(game_features_header + ../include/uibase/game_features/bsainvalidation.h + ../include/uibase/game_features/dataarchives.h + ../include/uibase/game_features/game_feature.h + ../include/uibase/game_features/gameplugins.h + ../include/uibase/game_features/igamefeatures.h + ../include/uibase/game_features/localsavegames.h + ../include/uibase/game_features/moddatachecker.h + ../include/uibase/game_features/moddatacontent.h + ../include/uibase/game_features/savegameinfo.h + ../include/uibase/game_features/scriptextender.h + ../include/uibase/game_features/unmanagedmods.h +) +set(formatters_header + ../include/uibase/formatters/enums.h + ../include/uibase/formatters/qt.h + ../include/uibase/formatters/random_access_containers.h + ../include/uibase/formatters/strings.h + ../include/uibase/formatters.h +) + add_library(uibase SHARED) -mo2_configure_uibase(uibase - WARNINGS ON - EXTERNAL_WARNINGS ON - TRANSLATIONS OFF - PUBLIC_DEPENDS Qt::Widgets Qt::Network Qt::QuickWidgets - PRIVATE_DEPENDS boost boost::thread Qt::Qml Qt::Quick spdlog) -target_compile_definitions(uibase PRIVATE -DUIBASE_EXPORT) -mo2_install_target(uibase) - -mo2_add_filter(NAME src/interfaces GROUPS - ifiletree - imoinfo - installationtester - iplugin - iplugindiagnose - ipluginfilemapper - iplugingame - iplugingamefeatures - iplugininstaller - iplugininstallercustom - iplugininstallersimple - ipluginlist - ipluginmodpage - ipluginpreview - ipluginproxy - iplugintool - iprofile - isavegame - isavegameinfowidget - iinstallationmanager - imodinterface - imodlist - imodrepositorybridge +mo2_configure_target(uibase NO_SOURCES WARNINGS ON EXTERNAL_WARNINGS ON) +mo2_default_source_group() + +mo2_target_sources(uibase + FOLDER src + PRIVATE + ${root_headers} + delayedfilewriter.cpp + diagnosisreport.cpp + errorcodes.cpp + eventfilter.cpp + executableinfo.cpp + filesystemutilities.cpp + guessedvalue.cpp + json.cpp + log.cpp + modrepositoryfileinfo.cpp + nxmurl.cpp + pch.cpp + pluginrequirements.cpp + pluginsetting.cpp + registry.cpp + report.cpp + safewritefile.cpp + scopeguard.cpp + steamutility.cpp + strings.cpp + utility.cpp + versioninfo.cpp ) -mo2_add_filter(NAME src/tutorials GROUPS - tutorabledialog - tutorialcontrol - tutorialmanager +mo2_target_sources(uibase + FOLDER src/interfaces + PRIVATE + ${interface_headers} + ifiletree.cpp + imodrepositorybridge.cpp + imoinfo.cpp + iplugininstaller.cpp ) -mo2_add_filter(NAME src/widgets GROUPS - finddialog - lineeditclear - questionboxmemory - sortabletreewidget - taskprogressmanager - textviewer - expanderwidget - filterwidget - linklabel - widgetutility +mo2_target_sources(uibase + FOLDER src/tutorials + PRIVATE + ${tutorial_headers} + tutorabledialog.cpp + tutorialcontrol.cpp + tutorialmanager.cpp ) -get_target_property(game_features uibase SOURCES) -list(FILTER game_features INCLUDE REGEX ".*game_features.*") -list(TRANSFORM game_features REPLACE ".*game_features[/\\](.*)[.]h" "game_features/\\1") +mo2_target_sources(uibase + FOLDER src/widgets + PRIVATE + ${widget_headers} + expanderwidget.cpp + finddialog.cpp + lineeditclear.cpp + linklabel.cpp + questionboxmemory.cpp + sortabletreewidget.cpp + taskprogressmanager.cpp + textviewer.cpp + widgetutility.cpp + filterwidget.cpp +) -mo2_add_filter(NAME src/game_features GROUPS - ${game_features} +mo2_target_sources(uibase FOLDER src/formatters PRIVATE ${formatters_header}) +mo2_target_sources(uibase FOLDER src/game_features PRIVATE ${game_features_header}) + +target_sources(uibase + PRIVATE + finddialog.ui + questionboxmemory.ui + taskdialog.ui + textviewer.ui + + version.rc + + ${root_headers} + pch.h + + PUBLIC + FILE_SET HEADERS + BASE_DIRS ${CMAKE_CURRENT_LIST_DIR}/../include + FILES + ${root_headers} + ${interface_headers} + ${tutorial_headers} + ${widget_headers} + ${game_features_header} + ${formatters_header} ) -get_target_property(formatters uibase SOURCES) -list(FILTER formatters INCLUDE REGEX ".*formatters.*") -list(TRANSFORM formatters REPLACE ".*formatters[/\\](.*)[.]h" "formatters/\\1") +set_target_properties(uibase PROPERTIES DEBUG_POSTFIX d) + +# TODO: remove this after fixing UIBase #include<> directives +target_include_directories(uibase PRIVATE + $ + $ +) + +add_library(mo2::uibase ALIAS uibase) + +target_compile_definitions(uibase PRIVATE -DUIBASE_EXPORT SPDLOG_USE_STD_FORMAT) + +target_link_libraries(uibase + PUBLIC Qt6::Widgets Qt6::Network Qt6::QuickWidgets + PRIVATE spdlog::spdlog_header_only Qt6::Qml Qt6::Quick Version) -mo2_add_filter(NAME src/formatters GROUPS - ${formatters} +# installation +install(TARGETS uibase EXPORT uibaseTargets FILE_SET HEADERS) +install(FILES $ DESTINATION pdb) +install(EXPORT uibaseTargets + FILE mo2-uibase-targets.cmake + NAMESPACE mo2:: + DESTINATION lib/cmake/mo2-uibase ) diff --git a/src/SConscript b/src/SConscript deleted file mode 100644 index 2d95af1c..00000000 --- a/src/SConscript +++ /dev/null @@ -1,52 +0,0 @@ -Import('qt_env') - -env = qt_env.Clone() - -modules = [ - 'Script', - 'Core', - 'Gui', - 'Declarative' -] - -if env['QT_MAJOR_VERSION'] > 4: - modules += [ - 'Widgets', - 'Qml', - 'QuickWidgets', - 'WinExtras' - ] - -env.EnableQtModules(*modules) - -env.Uic(Glob('*.ui')) - -env.AppendUnique(LIBS = ['user32', 'shell32', 'ole32']) - -# We have to 'persuade' moc to generate certain other targets and inject them -# into the list of cpps -targets = env.AddExtraMoc(env.Glob('*.h')) - -# Note the order of this is important, or you can pick up the wrong report.h... -env.AppendUnique(CPPPATH = [ - '.', # Why is this necessary? - '${BOOSTPATH}', -]) - -env.AppendUnique(CPPDEFINES = [ - 'UIBASE_LIBRARY', - 'UIBASE_EXPORT' -]) - -#CONFIG(debug, debug|release) { -#} else { -# QMAKE_CXXFLAGS += /Zi /GL -# QMAKE_LFLAGS += /DEBUG /LTCG /LARGEADDRESSAWARE /OPT:REF /OPT:ICF -#} - -lib = env.SharedLibrary('uibase', env.Glob('*.cpp') + targets) - -env.InstallModule(lib) - -res = env['QT_USED_MODULES'] -Return('res') diff --git a/src/log.cpp b/src/log.cpp index 5aac373d..2b5cd173 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -3,10 +3,8 @@ #include "utility.h" #include -#pragma warning(push) -#pragma warning(disable : 4668) -#include -#pragma warning(pop) +#include +#include #pragma warning(push) #pragma warning(disable : 4365) @@ -261,7 +259,7 @@ void Logger::addToBlacklist(const std::string& filter, const std::string& replac bool present = false; for (BlacklistEntry& e : m_conf.blacklist) { - if (boost::algorithm::iequals(e.filter, filter)) { + if (iequals(e.filter, filter)) { e.replacement = replacement; present = true; break; @@ -280,7 +278,7 @@ void Logger::removeFromBlacklist(const std::string& filter) } for (auto it = m_conf.blacklist.begin(); it != m_conf.blacklist.end();) { - if (boost::algorithm::iequals(it->filter, filter)) { + if (iequals(it->filter, filter)) { it = m_conf.blacklist.erase(it); } else { ++it; @@ -395,11 +393,4 @@ void doLogImpl(spdlog::logger& lg, Levels lv, const std::string& s) noexcept } } -void ireplace_all(std::string& input, std::string const& search, - std::string const& replace) noexcept -{ - // call boost here to avoid bringing the boost include in the header - boost::algorithm::ireplace_all(input, search, replace); -} - } // namespace MOBase::log::details diff --git a/src/strings.cpp b/src/strings.cpp new file mode 100644 index 00000000..ef84fb04 --- /dev/null +++ b/src/strings.cpp @@ -0,0 +1,46 @@ +#include "strings.h" + +#include +#include + +namespace MOBase +{ + +// this is strongly inspired from boost +class is_iequal +{ + std::locale m_loc; + +public: + is_iequal(const std::locale& loc = std::locale()) : m_loc{loc} {} + + template + bool operator()(const T1& Arg1, const T2& Arg2) const + { + return std::toupper(Arg1, m_loc) == std::toupper(Arg2, m_loc); + } +}; + +bool iequals(std::string_view lhs, std::string_view rhs) +{ + return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), is_iequal()); +} + +void ireplace_all(std::string& input, std::string_view search, + std::string_view replace) noexcept +{ + const auto search_length = static_cast(search.size()); + const auto replace_length = replace.size(); + auto it = input.begin(); + while (input.end() - it >= search_length) { + const auto search_end = it + search_length; + if (iequals(std::string_view(it, search_end), search)) { + input.replace(it, search_end, replace); + it += static_cast(replace_length); + } else { + ++it; + } + } +} + +} // namespace MOBase diff --git a/src/uibase_en.ts b/src/uibase_en.ts new file mode 100644 index 00000000..7f02320f --- /dev/null +++ b/src/uibase_en.ts @@ -0,0 +1,407 @@ + + + + + FilterWidget + + + Filter options + + + + + Use regular expressions + + + + + Use regular expressions in filters + + + + + Case sensitive + + + + + Make regular expressions case sensitive (/i) + leave "(/i)" verbatim + + + + + Extended + + + + + Ignores unescaped whitespace in regular expressions (/x) + leave "(/x)" verbatim + + + + + Keep selection in view + + + + + Scroll to keep the current selection in view after filtering + + + + + FindDialog + + + Find + + + + + Find what: + + + + + + Search term + + + + + + Find next occurence from current file position. + + + + + &Find Next + + + + + + + Close + + + + + QObject + + + Filter + + + + + One of the following plugins must be enabled: %1. + + + + + This plugin can only be enabled if the '%1' plugin is installed and enabled. + + + + + This plugin can only be enabled for the following game(s): %1. + + + + + + + + + + + INI file is read-only + + + + + + Mod Organizer is attempting to write to "%1" which is currently set to read-only. + + + + + + Clear the read-only flag + + + + + + Allow the write once + + + + + + The file will be set to read-only again. + + + + + + Skip this file + + + + + + Error + + + + + You can reset these choices by clicking "Reset Dialog Choices" in the General tab of the Settings + + + + + Always ask + + + + + + Remember my choice + + + + + Remember my choice for %1 + + + + + Failed to save '%1', could not create a temporary file: %2 (error %3) + Failed to save '{}', could not create a temporary file: {} (error {}) + + + + + removal of "%1" failed: %2 + + + + + removal of "%1" failed + + + + + "%1" doesn't exist (remove) + + + + + Error %1 + + + + + + You have an invalid custom browser command in the settings. + + + + + + failed to create directory "%1" + + + + + + failed to copy "%1" to "%2" + + + + + %1 B + + + + + %1 KB + + + + + %1 MB + + + + + %1 GB + + + + + %1 TB + + + + + %1 B/s + + + + + %1 KB/s + + + + + %1 MB/s + + + + + %1 GB/s + + + + + %1 TB/s + + + + + QuestionBoxMemory + + + Remember selection + + + + + Remember selection only for %1 + + + + + TaskDialog + + + Dialog + + + + + icon + + + + + dummy main text + + + + + dummy content text + + + + + dummy button + + + + + dummy checkbox + + + + + Details + + + + + TextViewer + + + Log Viewer + + + + + Placeholder + + + + + Show Whitespace + + + + + Save changes? + + + + + Do you want to save changes to %1? + + + + + failed to write to %1 + + + + + file not found: %1 + + + + + Save + + + + + TutorialControl + + + Tutorial failed to start, please check "mo_interface.log" for details. + + + + + TutorialManager + + + tutorial manager not set up yet + + + + + uibase + + + h + Time remaining hours + + + + + m + Time remaining minutes + + + + + s + Time remaining seconds + + + + diff --git a/src/version.rc b/src/version.rc index a171ba51..ae1d0eeb 100644 --- a/src/version.rc +++ b/src/version.rc @@ -3,14 +3,14 @@ // If VS_FF_PRERELEASE is not set, MO labels the build as a release and uses VER_FILEVERSION to determine version number. // Otherwise, if letters are used in VER_FILEVERSION_STR, uses the full MOBase::VersionInfo parser // Otherwise, uses the numbers from VER_FILEVERSION and sets the release type as pre-alpha -#define VER_FILEVERSION 2,5.2 -#define VER_FILEVERSION_STR "2.5.2\0" +#define VER_FILEVERSION 2,6,0 +#define VER_FILEVERSION_STR "2.6.0-dev.0\0" VS_VERSION_INFO VERSIONINFO FILEVERSION VER_FILEVERSION PRODUCTVERSION VER_FILEVERSION FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -FILEFLAGS (0) +FILEFLAGS VS_FF_PRERELEASE FILEOS VOS__WINDOWS32 FILETYPE VFT_APP FILESUBTYPE (0) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 022cd8ca..54f02ead 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,5 +1,11 @@ cmake_minimum_required(VERSION 3.16) add_executable(uibase-tests EXCLUDE_FROM_ALL) -mo2_configure_tests(uibase-tests - WARNINGS OFF DEPENDS uibase) +target_sources(uibase-tests + PRIVATE + test_formatters.cpp + test_ifiletree.cpp + test_strings.cpp +) +mo2_configure_tests(uibase-tests NO_SOURCES WARNINGS 4) +target_link_libraries(uibase-tests PRIVATE uibase) diff --git a/tests/cmake/CMakeLists.txt b/tests/cmake/CMakeLists.txt new file mode 100644 index 00000000..2a8e34a7 --- /dev/null +++ b/tests/cmake/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.16) + +project(uibase-tests-cmake) + +find_package(mo2-uibase CONFIG REQUIRED) + +add_library(plugin SHARED) +target_sources(plugin PRIVATE plugin.cpp) +target_link_libraries(plugin PRIVATE mo2::uibase) diff --git a/tests/cmake/plugin.cpp b/tests/cmake/plugin.cpp new file mode 100644 index 00000000..8356dcd6 --- /dev/null +++ b/tests/cmake/plugin.cpp @@ -0,0 +1,4 @@ +#include + +class Plugin : public MOBase::IPlugin +{}; diff --git a/tests/test_formatters.cpp b/tests/test_formatters.cpp index 94fc2640..65b5d079 100644 --- a/tests/test_formatters.cpp +++ b/tests/test_formatters.cpp @@ -6,7 +6,7 @@ #include #include -#include "formatters.h" +#include #include diff --git a/tests/test_ifiletree.cpp b/tests/test_ifiletree.cpp index aefacd34..3a903ad6 100644 --- a/tests/test_ifiletree.cpp +++ b/tests/test_ifiletree.cpp @@ -7,7 +7,7 @@ #include #include -#include "ifiletree.h" +#include std::ostream& operator<<(std::ostream& os, const QString& str) { diff --git a/tests/test_strings.cpp b/tests/test_strings.cpp new file mode 100644 index 00000000..69dadbbf --- /dev/null +++ b/tests/test_strings.cpp @@ -0,0 +1,33 @@ +#pragma warning(push) +#pragma warning(disable : 4668) +#include +#pragma warning(pop) + +#include + +#include + +using namespace MOBase; + +TEST(StringsTest, IEquals) +{ + ASSERT_TRUE(iequals("hello world", "HelLO WOrlD")); +} + +TEST(StringsTest, IReplaceAll) +{ + auto ireplace_all = [](std::string_view input, std::string_view search, + std::string_view replace) { + std::string s_input{input}; + MOBase::ireplace_all(s_input, search, replace); + return s_input; + }; + + ASSERT_EQ("", ireplace_all("", "world", "MO2")); + ASSERT_EQ("Hello World!", ireplace_all("Hello World!", "Test", "MO2")); + ASSERT_EQ("replace a stuff with a stuff a", + ireplace_all("replace some stuff with some stuff some", "some", "a")); + ASSERT_EQ("replace a stuff with a stuff som", + ireplace_all("replace some stuff with some stuff som", "some", "a")); + ASSERT_EQ("1YYY3YYY2", ireplace_all("1aBc3AbC2", "abC", "YYY")); +} diff --git a/vcpkg-configuration.json b/vcpkg-configuration.json new file mode 100644 index 00000000..40e0b2a4 --- /dev/null +++ b/vcpkg-configuration.json @@ -0,0 +1,21 @@ +{ + "default-registry": { + "kind": "git", + "repository": "https://github.com/Microsoft/vcpkg", + "baseline": "f61a294e765b257926ae9e9d85f96468a0af74e7" + }, + "registries": [ + { + "kind": "git", + "repository": "https://github.com/Microsoft/vcpkg", + "baseline": "f61a294e765b257926ae9e9d85f96468a0af74e7", + "packages": ["boost*", "boost-*"] + }, + { + "kind": "git", + "repository": "https://github.com/ModOrganizer2/vcpkg-registry", + "baseline": "09c389ef37bcec89b28f13105be959fecf4f3975", + "packages": ["mo2-cmake", "spdlog"] + } + ] +} diff --git a/vcpkg.json b/vcpkg.json new file mode 100644 index 00000000..563f4f91 --- /dev/null +++ b/vcpkg.json @@ -0,0 +1,15 @@ +{ + "dependencies": ["mo2-cmake", "spdlog"], + "overrides": [ + { + "name": "spdlog", + "version": "1.14.1" + } + ], + "features": { + "testing": { + "description": "Build UI Base tests.", + "dependencies": ["gtest"] + } + } +} From 1dc631fc6411cbdfb0c07e22233290309c32fad1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Capelle?= Date: Mon, 5 Aug 2024 11:40:46 +0200 Subject: [PATCH 02/12] Move to custom semver versioning for MO2. (#154) --- .gitignore | 1 + include/uibase/exceptions.h | 1 + include/uibase/imoinfo.h | 8 +- include/uibase/versioning.h | 181 +++++++++++++++++++++++ src/CMakeLists.txt | 4 +- src/iplugininstaller.cpp | 18 --- src/pluginsetting.cpp | 24 ---- src/versioning.cpp | 278 ++++++++++++++++++++++++++++++++++++ tests/CMakeLists.txt | 1 + tests/cmake/CMakeLists.txt | 1 + tests/test_versioning.cpp | 90 ++++++++++++ 11 files changed, 562 insertions(+), 45 deletions(-) create mode 100644 include/uibase/versioning.h delete mode 100644 src/iplugininstaller.cpp delete mode 100644 src/pluginsetting.cpp create mode 100644 src/versioning.cpp create mode 100644 tests/test_versioning.cpp diff --git a/.gitignore b/.gitignore index bcdbd6a5..a55b4baf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ edit +.vscode CMakeLists.txt.user /msbuild.log /*std*.log diff --git a/include/uibase/exceptions.h b/include/uibase/exceptions.h index 433b9be7..c89a4833 100644 --- a/include/uibase/exceptions.h +++ b/include/uibase/exceptions.h @@ -3,6 +3,7 @@ #include +#include #include #include "dllimport.h" diff --git a/include/uibase/imoinfo.h b/include/uibase/imoinfo.h index e4f072a8..bf6588d5 100644 --- a/include/uibase/imoinfo.h +++ b/include/uibase/imoinfo.h @@ -35,6 +35,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include "imodlist.h" #include "iprofile.h" #include "versioninfo.h" +#include "versioning.h" namespace MOBase { @@ -121,7 +122,12 @@ class QDLLEXPORT IOrganizer : public QObject /** * @return the running version of Mod Organizer */ - virtual VersionInfo appVersion() const = 0; + [[deprecated]] virtual VersionInfo appVersion() const = 0; + + /** + * @return the running version of Mod Organizer + */ + virtual Version version() const = 0; /** * @brief create a new mod with the specified name diff --git a/include/uibase/versioning.h b/include/uibase/versioning.h new file mode 100644 index 00000000..c4f95419 --- /dev/null +++ b/include/uibase/versioning.h @@ -0,0 +1,181 @@ +#pragma once + +#include +#include +#include +#include + +#include +#include + +#include "dllimport.h" +#include "exceptions.h" + +namespace MOBase +{ + +class InvalidVersionException : public Exception +{ +public: + using Exception::Exception; +}; + +// class representing a Version object +// +// valid versions are an "extension" of SemVer (see https://semver.org/) with the +// following tweaks: +// - version can have a sub-patch, i.e., x.y.z.p, which are normally not allowed by +// SemVer +// - non-integer pre-release identifiers are limited to dev, alpha (a), beta (b) and rc, +// and dev is lower than alpha (according to SemVer, the pre-release should be +// ordered alphabetically) +// - the '-' between version and pre-release can be made optional, and also the '.' +// between pre-releases segment +// +// the extension from SemVer are only meant to be used by MO2 and USVFS versioning, +// plugins and extensions should follow SemVer standard (and not use dev), this is +// mainly +// - for back-compatibility purposes, because USVFS versioning contains sub-patches and +// there are old MO2 releases with sub-patch +// - because MO2 is not going to become MO3, so having an extra level make sense +// +// unlike VersionInfo, this class is immutable and only hold valid versions +// +class QDLLEXPORT Version +{ +public: + enum class ParseMode + { + // official semver parsing with pre-release limited to dev, alpha/a, beta/b and rc + // + SemVer, + + // MO2 parsing, e.g., 2.5.1rc1 - this either parse a string with no pre-release + // information (e.g. 2.5.1) or with a single pre-release + a version (e.g., 2.5.1a1 + // or 2.5.2rc1) + // + // this mode can parse sub-patch (SemVer mode cannot) + // + MO2 + }; + + enum class FormatMode + { + // show subpatch even if subpatch is 0 + // + ForceSubPatch = 0b0001, + + // do not add separators between version and pre-release (-) or between pre-release + // segments (.) + // + NoSeparator = 0b0010, + + // uses short form for alpha and beta (a/b instead of alpha/beta) + // + ShortAlphaBeta = 0b0100, + + // do not add metadata even if present + // + NoMetadata = 0b1000 + }; + Q_DECLARE_FLAGS(FormatModes, FormatMode); + + // condensed format, no separator, short alpha/beta and no metadata + // + static constexpr auto FormatCondensed = FormatModes{ + FormatMode::NoSeparator, FormatMode::ShortAlphaBeta, FormatMode::NoMetadata}; + + enum class ReleaseType + { + Development, // -dev + Alpha, // -alpha, -a + Beta, // -beta, -b + ReleaseCandidate, // -rc + }; + using enum ReleaseType; + +public: // parsing + // parse version from the given string, throw InvalidVersionException if the string + // cannot be parsed + // + static Version parse(QString const& value, ParseMode mode = ParseMode::SemVer); + +public: // constructors + Version(int major, int minor, int patch, QString metadata = {}); + Version(int major, int minor, int patch, int subpatch, QString metadata = {}); + + Version(int major, int minor, int patch, ReleaseType type, QString metadata = {}); + Version(int major, int minor, int patch, int subpatch, ReleaseType type, + QString metadata = {}); + + Version(int major, int minor, int patch, ReleaseType type, int prerelease, + QString metadata = {}); + Version(int major, int minor, int patch, int subpatch, ReleaseType type, + int prerelease, QString metadata = {}); + + Version(int major, int minor, int patch, int subpatch, + std::vector> prereleases, + QString metadata = {}); + +public: // special member functions + Version(const Version&) = default; + Version(Version&&) = default; + + Version& operator=(const Version&) = default; + Version& operator=(Version&&) = default; + +public: + // check if this version corresponds to a pre-release version (dev, alpha, beta, etc.) + // + bool isPreRelease() const { return !m_PreReleases.empty(); } + + // retrieve major, minor, patch and sub-patch of this version + // + int major() const { return m_Major; } + int minor() const { return m_Minor; } + int patch() const { return m_Patch; } + int subpatch() const { return m_SubPatch; } + + // retrieve pre-releases information for this version + // + const auto& preReleases() const { return m_PreReleases; } + + // retrieve build metadata, if any, otherwise return an empty string + // + const auto& buildMetadata() const { return m_BuildMetadata; } + + // convert this version to a string + // + QString string(const FormatModes& modes = {}) const; + +private: + // major.minor.patch + int m_Major, m_Minor, m_Patch, m_SubPatch; + + // pre-release information + std::vector> m_PreReleases; + + // metadata + QString m_BuildMetadata; +}; + +QDLLEXPORT std::strong_ordering operator<=>(const Version& lhs, const Version& rhs); + +inline bool operator==(const Version& lhs, const Version& rhs) +{ + return (lhs <=> rhs) == 0; +} + +Q_DECLARE_OPERATORS_FOR_FLAGS(Version::FormatModes); + +} // namespace MOBase + +template +struct std::formatter : std::formatter +{ + template + FmtContext::iterator format(const MOBase::Version& v, FmtContext& ctx) const + { + return std::formatter::format(v.string(), ctx); + } +}; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5b096a67..fa1d0a66 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -30,6 +30,7 @@ set(root_headers ../include/uibase/steamutility.h ../include/uibase/strings.h ../include/uibase/utility.h + ../include/uibase/versioning.h ../include/uibase/versioninfo.h ) set(interface_headers @@ -115,7 +116,6 @@ mo2_target_sources(uibase nxmurl.cpp pch.cpp pluginrequirements.cpp - pluginsetting.cpp registry.cpp report.cpp safewritefile.cpp @@ -123,6 +123,7 @@ mo2_target_sources(uibase steamutility.cpp strings.cpp utility.cpp + versioning.cpp versioninfo.cpp ) @@ -133,7 +134,6 @@ mo2_target_sources(uibase ifiletree.cpp imodrepositorybridge.cpp imoinfo.cpp - iplugininstaller.cpp ) mo2_target_sources(uibase diff --git a/src/iplugininstaller.cpp b/src/iplugininstaller.cpp deleted file mode 100644 index 79e62472..00000000 --- a/src/iplugininstaller.cpp +++ /dev/null @@ -1,18 +0,0 @@ -/* -Copyright (C) 2012 Sebastian Herbord. All rights reserved. - -This file is part of Mod Organizer. - -Mod Organizer is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Mod Organizer is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with Mod Organizer. If not, see . -*/ diff --git a/src/pluginsetting.cpp b/src/pluginsetting.cpp deleted file mode 100644 index cce84eb6..00000000 --- a/src/pluginsetting.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/* -Copyright (C) 2012 Sebastian Herbord. All rights reserved. - -This file is part of Mod Organizer. - -Mod Organizer is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Mod Organizer is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with Mod Organizer. If not, see . -*/ - -#include "pluginsetting.h" - -namespace MOBase -{ -} // namespace MOBase diff --git a/src/versioning.cpp b/src/versioning.cpp new file mode 100644 index 00000000..ddc0ed6a --- /dev/null +++ b/src/versioning.cpp @@ -0,0 +1,278 @@ +#include "versioning.h" + +#include +#include +#include + +#include "formatters.h" + +// official semver regex +static const QRegularExpression s_SemVerStrictRegEx{ + R"(^(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)(?:-(?P(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$)"}; + +// for MO2, to match stuff like 1.2.3rc1 or v1.2.3a1+XXX +static const QRegularExpression s_SemVerMO2RegEx{ + R"(^v?(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)(?:\.(?P0|[1-9]\d*))?(?:(?Pdev|a|alpha|b|beta|rc)(?P0|[1-9](?:[.0-9])*))?(?:\+(?P[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$)"}; + +// match from value to release type +static const std::unordered_map + s_StringToRelease{{"dev", MOBase::Version::Development}, + {"alpha", MOBase::Version::Alpha}, + {"a", MOBase::Version::Alpha}, + {"beta", MOBase::Version::Beta}, + {"b", MOBase::Version::Beta}, + {"rc", MOBase::Version::ReleaseCandidate}}; + +namespace MOBase +{ + +namespace +{ + + Version parseVersionSemVer(QString const& value) + { + const auto match = s_SemVerStrictRegEx.match(value); + + if (!match.hasMatch()) { + throw InvalidVersionException( + QString::fromStdString(std::format("invalid version string: '{}'", value))); + } + + const auto major = match.captured("major").toInt(); + const auto minor = match.captured("minor").toInt(); + const auto patch = match.captured("patch").toInt(); + + std::vector> prereleases; + for (auto& part : match.captured("prerelease") + .split(".", Qt::SplitBehaviorFlags::SkipEmptyParts)) { + // try to extract an int + bool ok = true; + const auto intValue = part.toInt(&ok); + if (ok) { + prereleases.push_back(intValue); + continue; + } + + // check if we have a valid prerelease type + const auto it = s_StringToRelease.find(part.toLower()); + if (it == s_StringToRelease.end()) { + throw InvalidVersionException( + QString::fromStdString(std::format("invalid prerelease type: '{}'", part))); + } + + prereleases.push_back(it->second); + } + + const auto buildMetadata = match.captured("buildmetadata").trimmed(); + + return Version(major, minor, patch, 0, prereleases, buildMetadata); + } + + Version parseVersionMO2(QString const& value) + { + const auto match = s_SemVerMO2RegEx.match(value); + + if (!match.hasMatch()) { + throw InvalidVersionException( + QString::fromStdString(std::format("invalid version string: '{}'", value))); + } + + const auto major = match.captured("major").toInt(); + const auto minor = match.captured("minor").toInt(); + const auto patch = match.captured("patch").toInt(); + + const auto subpatch = match.captured("subpatch").toInt(); + + // unlike semver, the regex will only match valid values + std::vector> prereleases; + if (match.hasCaptured("type")) { + prereleases.push_back(s_StringToRelease.at(match.captured("type"))); + + // for version with decimal point, e.g., 2.4.1rc1.1, we split the components into + // pre-release components to get {rc, 1, 1} - this works fine since {rc, 1} < {rc, + // 1, 1} + // + for (const auto& preVersion : + match.captured("prerelease").split(".", Qt::SkipEmptyParts)) { + prereleases.push_back(preVersion.toInt()); + } + } + + const auto buildMetadata = match.captured("buildmetadata").trimmed(); + + return Version(major, minor, patch, subpatch, prereleases, buildMetadata); + } + +} // namespace + +Version Version::parse(QString const& value, ParseMode mode) +{ + return mode == ParseMode::SemVer ? parseVersionSemVer(value) : parseVersionMO2(value); +} + +// constructors + +Version::Version(int major, int minor, int patch, QString metadata) + : Version(major, minor, patch, 0, std::move(metadata)) +{} +Version::Version(int major, int minor, int patch, int subpatch, QString metadata) + : m_Major{major}, m_Minor{minor}, m_Patch{patch}, m_SubPatch{subpatch}, + m_PreReleases{}, m_BuildMetadata{std::move(metadata)} +{} + +Version::Version(int major, int minor, int patch, ReleaseType type, QString metadata) + : Version(major, minor, patch, 0, type, std::move(metadata)) +{} +Version::Version(int major, int minor, int patch, int subpatch, ReleaseType type, + QString metadata) + : m_Major{major}, m_Minor{minor}, m_Patch{patch}, m_SubPatch{subpatch}, + m_PreReleases{type}, m_BuildMetadata{std::move(metadata)} +{} + +Version::Version(int major, int minor, int patch, ReleaseType type, int prerelease, + QString metadata) + : Version(major, minor, patch, 0, type, prerelease, std::move(metadata)) +{} +Version::Version(int major, int minor, int patch, int subpatch, ReleaseType type, + int prerelease, QString metadata) + : Version(major, minor, patch, subpatch, {type, prerelease}, std::move(metadata)) +{} + +Version::Version(int major, int minor, int patch, int subpatch, + std::vector> prereleases, + QString metadata) + : m_Major{major}, m_Minor{minor}, m_Patch{patch}, m_SubPatch{subpatch}, + m_PreReleases{std::move(prereleases)}, m_BuildMetadata{std::move(metadata)} +{} + +// string + +QString Version::string(const FormatModes& modes) const +{ + const bool noSeparator = modes.testFlag(FormatMode::NoSeparator); + const bool shortAlphaBeta = modes.testFlag(FormatMode::ShortAlphaBeta); + auto value = std::format("{}.{}.{}", m_Major, m_Minor, m_Patch); + + if (m_SubPatch || modes.testFlag(FormatMode::ForceSubPatch)) { + value += std::format(".{}", m_SubPatch); + } + + if (!m_PreReleases.empty()) { + if (!noSeparator) { + value += "-"; + } + for (std::size_t i = 0; i < m_PreReleases.size(); ++i) { + value += std::visit( + [shortAlphaBeta](auto const& pre) -> std::string { + if constexpr (std::is_same_v) { + switch (pre) { + case Development: + return "dev"; + case Alpha: + return shortAlphaBeta ? "a" : "alpha"; + case Beta: + return shortAlphaBeta ? "b" : "beta"; + case ReleaseCandidate: + return "rc"; + } + return ""; + } else { + return std::to_string(pre); + } + }, + m_PreReleases[i]); + if (!noSeparator && i < m_PreReleases.size() - 1) { + value += "."; + } + } + } + + if (!modes.testFlag(FormatMode::NoMetadata) && !m_BuildMetadata.isEmpty()) { + value += "+" + m_BuildMetadata.toStdString(); + } + + return QString::fromStdString(value); +} + +namespace +{ + // consume the given iterator until the given end iterator or until a non-zero value + // is found + // + template + It consumePreReleaseZeros(It it, It end) + { + for (; it != end; ++it) { + if (!std::holds_alternative(*it) != 0 || std::get(*it) != 0) { + break; + } + } + return it; + }; +} // namespace + +std::strong_ordering operator<=>(const Version& lhs, const Version& rhs) +{ + auto mmp_cmp = + std::forward_as_tuple(lhs.major(), lhs.minor(), lhs.patch(), lhs.subpatch()) <=> + std::forward_as_tuple(rhs.major(), rhs.minor(), rhs.patch(), rhs.subpatch()); + + // major.minor.patch have precedence over everything else + if (mmp_cmp != std::strong_ordering::equal) { + return mmp_cmp; + } + + // handle cases were one is a pre-release and not the other - the pre-release is + // "less" than the release + if (lhs.isPreRelease() && !rhs.isPreRelease()) { + return std::strong_ordering::less; + } + + if (!lhs.isPreRelease() && rhs.isPreRelease()) { + return std::strong_ordering::greater; + } + + // compare pre-release fields + auto lhsIt = lhs.preReleases().begin(), rhsIt = rhs.preReleases().begin(); + for (; lhsIt != lhs.preReleases().end() && rhsIt != rhs.preReleases().end(); + ++lhsIt, ++rhsIt) { + + const auto &lhsPre = *lhsIt, rhsPre = *rhsIt; + + // if one is alpha/beta/etc. and the other is numeric, the alpha/beta/etc. is lower + // than the numeric one, which matches the index + auto pre_cmp = lhsPre.index() <=> rhsPre.index(); + if (pre_cmp != std::strong_ordering::equal) { + return pre_cmp; + } + + // compare the actual values + pre_cmp = lhsPre <=> rhsPre; + if (pre_cmp != std::strong_ordering::equal) { + return pre_cmp; + } + } + + // the code below does not follow semver 100% (I think) - basically, this makes stuff + // like 2.4.1rc1.0 equals to 2.4.1rc1, which according to semver is probably not right + // but is probably best for us + // + + // if we land here, we have consumed one of the pre-release, we skip all the 0 in the + // remaining one + lhsIt = consumePreReleaseZeros(lhsIt, lhs.preReleases().end()); + rhsIt = consumePreReleaseZeros(rhsIt, rhs.preReleases().end()); + + const auto lhsConsumed = lhsIt == lhs.preReleases().end(), + rhsConsumed = rhsIt == rhs.preReleases().end(); + + if (lhsConsumed && rhsConsumed) { + return std::strong_ordering::equal; + } else if (!lhsConsumed) { + return std::strong_ordering::greater; + } else { + return std::strong_ordering::less; + } +} + +} // namespace MOBase diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 54f02ead..ac17234a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -6,6 +6,7 @@ target_sources(uibase-tests test_formatters.cpp test_ifiletree.cpp test_strings.cpp + test_versioning.cpp ) mo2_configure_tests(uibase-tests NO_SOURCES WARNINGS 4) target_link_libraries(uibase-tests PRIVATE uibase) diff --git a/tests/cmake/CMakeLists.txt b/tests/cmake/CMakeLists.txt index 2a8e34a7..e1d636f7 100644 --- a/tests/cmake/CMakeLists.txt +++ b/tests/cmake/CMakeLists.txt @@ -7,3 +7,4 @@ find_package(mo2-uibase CONFIG REQUIRED) add_library(plugin SHARED) target_sources(plugin PRIVATE plugin.cpp) target_link_libraries(plugin PRIVATE mo2::uibase) +set_target_properties(plugin PROPERTIES CXX_STANDARD 20) diff --git a/tests/test_versioning.cpp b/tests/test_versioning.cpp new file mode 100644 index 00000000..08a346fd --- /dev/null +++ b/tests/test_versioning.cpp @@ -0,0 +1,90 @@ +#pragma warning(push) +#pragma warning(disable : 4668) +#include +#pragma warning(pop) + +#include +#include + +#include + +#include + +using namespace MOBase; + +using enum Version::ReleaseType; +using ParseMode = Version::ParseMode; + +TEST(VersioningTest, VersionParse) +{ + // TODO: add exceptions test + + // semver + ASSERT_EQ(Version(1, 0, 0), Version::parse("1.0.0")); + ASSERT_EQ(Version(1, 0, 0, Development, 1), Version::parse("1.0.0-dev.1")); + ASSERT_EQ(Version(1, 0, 0, Development, 2), Version::parse("1.0.0-dev.2")); + ASSERT_EQ(Version(1, 0, 0, Alpha), Version::parse("1.0.0-a")); + ASSERT_EQ(Version(1, 0, 0, Alpha), Version::parse("1.0.0-alpha")); + ASSERT_EQ(Version(1, 0, 0, 0, {Alpha, 1, Beta}), Version::parse("1.0.0-alpha.1.b")); + ASSERT_EQ(Version(1, 0, 0, Beta, 2), Version::parse("1.0.0-beta.2")); + ASSERT_EQ(Version(2, 5, 2, ReleaseCandidate, 1), Version::parse("2.5.2-rc.1")); + + // mo2 + ASSERT_EQ(Version(1, 0, 0), Version::parse("1.0.0", ParseMode::MO2)); + ASSERT_EQ(Version(1, 0, 0, Development, 1), + Version::parse("1.0.0dev1", ParseMode::MO2)); + ASSERT_EQ(Version(1, 0, 0, Development, 2), + Version::parse("1.0.0dev2", ParseMode::MO2)); + ASSERT_EQ(Version(1, 0, 0, Alpha, 1), Version::parse("1.0.0a1", ParseMode::MO2)); + ASSERT_EQ(Version(1, 0, 0, Alpha, 1), Version::parse("1.0.0alpha1", ParseMode::MO2)); + ASSERT_EQ(Version(1, 0, 0, Beta, 2), Version::parse("1.0.0beta2", ParseMode::MO2)); + ASSERT_EQ(Version(1, 0, 0, Beta, 2), Version::parse("1.0.0beta2", ParseMode::MO2)); + ASSERT_EQ(Version(2, 4, 1, 0, {ReleaseCandidate, 1, 1}), + Version::parse("2.4.1rc1.1", ParseMode::MO2)); + ASSERT_EQ(Version(2, 2, 2, 1, Beta, 2), + Version::parse("2.2.2.1beta2", ParseMode::MO2)); + ASSERT_EQ(Version(2, 5, 2, ReleaseCandidate, 1), + Version::parse("v2.5.2rc1", ParseMode::MO2)); + ASSERT_EQ(Version(2, 5, 2, ReleaseCandidate, 2), + Version::parse("2.5.2rc2", ParseMode::MO2)); +} + +TEST(VersioningTest, VersionString) +{ + ASSERT_EQ("1.0.0", Version(1, 0, 0).string()); + ASSERT_EQ("1.0.0-dev.1", Version(1, 0, 0, Development, 1).string()); + ASSERT_EQ("1.0.0-dev.2", Version(1, 0, 0, Development, 2).string()); + ASSERT_EQ("1.0.0-alpha", Version(1, 0, 0, Alpha).string()); + ASSERT_EQ("1.0.0-alpha.1.beta", Version(1, 0, 0, 0, {Alpha, 1, Beta}).string()); + ASSERT_EQ("1.0.0-beta.2", Version(1, 0, 0, Beta, 2).string()); + ASSERT_EQ("2.5.2-rc.1", Version(2, 5, 2, ReleaseCandidate, 1).string()); + ASSERT_EQ("2.5.2rc1", + Version(2, 5, 2, ReleaseCandidate, 1).string(Version::FormatCondensed)); +} + +TEST(VersioningTest, VersionCompare) +{ + // shortcut + using v = Version; + + // test from https://semver.org/ + ASSERT_TRUE(v(1, 0, 0) < v(2, 0, 0)); + ASSERT_TRUE(v(2, 0, 0) < v(2, 1, 0)); + ASSERT_TRUE(v(2, 1, 0) < v(2, 1, 1)); + + ASSERT_TRUE(v(1, 0, 0, Alpha) < v(1, 0, 0, Alpha, 1)); + ASSERT_TRUE(v(1, 0, 0, Alpha, 1) < v(1, 0, 0, 0, {Alpha, Beta})); + ASSERT_TRUE(v(1, 0, 0, 0, {Alpha, Beta}) < v(1, 0, 0, 1)); + ASSERT_TRUE(v(1, 0, 0, Beta) < v(1, 0, 0, Beta, 2)); + ASSERT_TRUE(v(1, 0, 0, Beta, 2) < v(1, 0, 0, Beta, 11)); + ASSERT_TRUE(v(1, 0, 0, Beta, 11) < v(1, 0, 0, ReleaseCandidate, 1)); + ASSERT_TRUE(v(1, 0, 0, ReleaseCandidate, 0) < v(1, 0, 0)); + + ASSERT_TRUE(v(2, 4, 1, 0, {ReleaseCandidate, 1, 0}) == + v(2, 4, 1, ReleaseCandidate, 1)); + ASSERT_TRUE(v(2, 4, 1, 0, {ReleaseCandidate, 1, 0}) < + v(2, 4, 1, 0, {ReleaseCandidate, 1, 1})); + ASSERT_TRUE(v(2, 4, 1, ReleaseCandidate, 1) < + v(2, 4, 1, 0, {ReleaseCandidate, 1, 1})); + ASSERT_TRUE(v(1, 0, 0) < v(2, 0, 0, Alpha)); +} From 7810e031aa2df6342c5670e0b1521d734934a23a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Capelle?= Date: Mon, 5 Aug 2024 13:43:27 +0200 Subject: [PATCH 03/12] Update Qt version in CI and bump MO2 VCPKG registry baseline. --- .github/workflows/build.yml | 2 +- vcpkg-configuration.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 893fa507..f685a376 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -26,7 +26,7 @@ jobs: - name: Install Qt uses: jurplel/install-qt-action@v3 with: - version: 6.7.0 + version: 6.7.1 modules: cache: true diff --git a/vcpkg-configuration.json b/vcpkg-configuration.json index 40e0b2a4..2e5c2a90 100644 --- a/vcpkg-configuration.json +++ b/vcpkg-configuration.json @@ -14,7 +14,7 @@ { "kind": "git", "repository": "https://github.com/ModOrganizer2/vcpkg-registry", - "baseline": "09c389ef37bcec89b28f13105be959fecf4f3975", + "baseline": "6e9492a38a7d5bfeeeaf80723fa821b42f3a26a8", "packages": ["mo2-cmake", "spdlog"] } ] From 643f77ed8a5e724e05a3bd4159b2d3bc23933393 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Capelle?= Date: Fri, 9 Aug 2024 12:47:13 +0200 Subject: [PATCH 04/12] Allow for external mo2-cmake (#160) * Create standalone feature for mo2-cmake. * Setup a QCoreApplication in tests main. --- .github/workflows/build.yml | 2 +- CMakePresets.json | 15 +++++++++------ tests/CMakeLists.txt | 3 ++- tests/test_main.cpp | 15 +++++++++++++++ tests/test_strings.cpp | 9 +++++++++ tests/translations/tests_en.qm | Bin 0 -> 141 bytes tests/translations/tests_en.ts | 11 +++++++++++ tests/translations/tests_fr.qm | Bin 0 -> 147 bytes tests/translations/tests_fr.ts | 11 +++++++++++ vcpkg-configuration.json | 21 --------------------- vcpkg.json | 21 ++++++++++++++++++++- 11 files changed, 78 insertions(+), 30 deletions(-) create mode 100644 tests/test_main.cpp create mode 100644 tests/translations/tests_en.qm create mode 100644 tests/translations/tests_en.ts create mode 100644 tests/translations/tests_fr.qm create mode 100644 tests/translations/tests_fr.ts delete mode 100644 vcpkg-configuration.json diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f685a376..e5ceb1be 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -36,7 +36,7 @@ jobs: - name: Configure UI Base build shell: pwsh run: | - cmake --preset vs2022-windows ` + cmake --preset vs2022-windows-standalone ` "-DCMAKE_PREFIX_PATH=${env:QT_ROOT_DIR}\msvc2019_64" ` "-DCMAKE_INSTALL_PREFIX=install" -DUIBASE_TESTING=ON diff --git a/CMakePresets.json b/CMakePresets.json index 0c06d1a3..f0e338e3 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -50,13 +50,16 @@ "inherits": ["cmake-dev", "vcpkg-dev"], "name": "vs2022-windows", "toolset": "v143" - } - ], - "buildPresets": [ + }, { - "name": "vs2022-windows", - "resolvePackageReferences": "on", - "configurePreset": "vs2022-windows" + "cacheVariables": { + "VCPKG_MANIFEST_FEATURES": { + "type": "STRING", + "value": "standalone;testing" + } + }, + "inherits": "vs2022-windows", + "name": "vs2022-windows-standalone" } ], "version": 4 diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ac17234a..7ff9e192 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -3,10 +3,11 @@ cmake_minimum_required(VERSION 3.16) add_executable(uibase-tests EXCLUDE_FROM_ALL) target_sources(uibase-tests PRIVATE + test_main.cpp test_formatters.cpp test_ifiletree.cpp test_strings.cpp test_versioning.cpp ) -mo2_configure_tests(uibase-tests NO_SOURCES WARNINGS 4) +mo2_configure_tests(uibase-tests NO_SOURCES NO_MAIN NO_MOCK WARNINGS 4) target_link_libraries(uibase-tests PRIVATE uibase) diff --git a/tests/test_main.cpp b/tests/test_main.cpp new file mode 100644 index 00000000..0399b433 --- /dev/null +++ b/tests/test_main.cpp @@ -0,0 +1,15 @@ +#include + +#include +#include + +int main(int argc, char** argv) +{ + QCoreApplication app(argc, argv); + QTranslator translator; + if (translator.load("tests_fr", "tests/translations")) { + app.installTranslator(&translator); + } + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/tests/test_strings.cpp b/tests/test_strings.cpp index 69dadbbf..56e75c9b 100644 --- a/tests/test_strings.cpp +++ b/tests/test_strings.cpp @@ -3,6 +3,8 @@ #include #pragma warning(pop) +#include + #include #include @@ -31,3 +33,10 @@ TEST(StringsTest, IReplaceAll) ireplace_all("replace some stuff with some stuff som", "some", "a")); ASSERT_EQ("1YYY3YYY2", ireplace_all("1aBc3AbC2", "abC", "YYY")); } + +// this is more a tests of the tests +TEST(StringsTest, Translation) +{ + ASSERT_EQ("Traduction en Français", + QCoreApplication::translate("uibase-tests", "Translate to French")); +} diff --git a/tests/translations/tests_en.qm b/tests/translations/tests_en.qm new file mode 100644 index 0000000000000000000000000000000000000000..d5ca50195d8899565e374e2405b25297d85c8ced GIT binary patch literal 141 zcmcE7ks@*G{hX<16=n7(EZlo{IRgU&YieG6Xs{EI#lil4=?@^ykO{<5%s@hoA%vlb zA(0`Ep_m~DNS83AGAIDad?4utlt~53Br{}ifHbiIv2aLHVqS4hVo9n(Nxp(xQEFat c20Kukr!+Guu{c$?B(=Dtn6U#W!o + + + + uibase-tests + + Translate to French + Translate to French + + + diff --git a/tests/translations/tests_fr.qm b/tests/translations/tests_fr.qm new file mode 100644 index 0000000000000000000000000000000000000000..80958d6e11a850ede8d6266c2a39254a0abce8ba GIT binary patch literal 147 zcmcE7ks@*G{hX<16=n7(EZlo{IRgU&Yg$pfTaXiw#lil4=?@^ykO{;I%s@hiA%vlb zA(0`4p_Cz+p#&(A&ydHUz>o?i-N15r49|foG8u|FKw8;=SU998F|Rl$u_RTYBwxX; gC^auRgB>W&Q<|BSSe&X`l3H9+%-8`GVPa+k0Fgu_wEzGB literal 0 HcmV?d00001 diff --git a/tests/translations/tests_fr.ts b/tests/translations/tests_fr.ts new file mode 100644 index 00000000..eed02a06 --- /dev/null +++ b/tests/translations/tests_fr.ts @@ -0,0 +1,11 @@ + + + + + uibase-tests + + Translate to French + Traduction en Français + + + diff --git a/vcpkg-configuration.json b/vcpkg-configuration.json deleted file mode 100644 index 2e5c2a90..00000000 --- a/vcpkg-configuration.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "default-registry": { - "kind": "git", - "repository": "https://github.com/Microsoft/vcpkg", - "baseline": "f61a294e765b257926ae9e9d85f96468a0af74e7" - }, - "registries": [ - { - "kind": "git", - "repository": "https://github.com/Microsoft/vcpkg", - "baseline": "f61a294e765b257926ae9e9d85f96468a0af74e7", - "packages": ["boost*", "boost-*"] - }, - { - "kind": "git", - "repository": "https://github.com/ModOrganizer2/vcpkg-registry", - "baseline": "6e9492a38a7d5bfeeeaf80723fa821b42f3a26a8", - "packages": ["mo2-cmake", "spdlog"] - } - ] -} diff --git a/vcpkg.json b/vcpkg.json index 563f4f91..6c1e8c9d 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -1,5 +1,5 @@ { - "dependencies": ["mo2-cmake", "spdlog"], + "dependencies": ["spdlog"], "overrides": [ { "name": "spdlog", @@ -7,9 +7,28 @@ } ], "features": { + "standalone": { + "description": "Build Standalone.", + "dependencies": ["mo2-cmake"] + }, "testing": { "description": "Build UI Base tests.", "dependencies": ["gtest"] } + }, + "vcpkg-configuration": { + "default-registry": { + "kind": "git", + "repository": "https://github.com/Microsoft/vcpkg", + "baseline": "8ae59b5b1329a51875abc71d528da93d9c3e8972" + }, + "registries": [ + { + "kind": "git", + "repository": "https://github.com/ModOrganizer2/vcpkg-registry", + "baseline": "84ff92223433d101738a3c6cef96fa6ae6a6f302", + "packages": ["mo2-cmake", "spdlog"] + } + ] } } From fcf96e35de7982c15067787db79730fd76f3c0df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Capelle?= Date: Fri, 23 May 2025 17:58:57 +0200 Subject: [PATCH 05/12] Update GH Action to use custom MO2 action. --- .github/workflows/build.yml | 29 +++++++++++------------------ CMakeLists.txt | 4 ++-- README.md | 4 ++-- 3 files changed, 15 insertions(+), 22 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e5ceb1be..d3aeffd4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,7 +2,7 @@ name: Build UIBase on: push: - branches: master + branches: [master] tags: - "*" pull_request: @@ -23,35 +23,28 @@ jobs: core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); - - name: Install Qt - uses: jurplel/install-qt-action@v3 + - name: Configure UIBase + id: configure-uibase + uses: ModOrganizer2/build-with-mob-action@dev/vcpkg with: - version: 6.7.1 - modules: - cache: true - - - uses: actions/checkout@v4 - - uses: lukka/run-vcpkg@v11 - - - name: Configure UI Base build - shell: pwsh - run: | - cmake --preset vs2022-windows-standalone ` - "-DCMAKE_PREFIX_PATH=${env:QT_ROOT_DIR}\msvc2019_64" ` - "-DCMAKE_INSTALL_PREFIX=install" -DUIBASE_TESTING=ON + # skip build because we are going to build both Debug and RelWithDebInfo here + mo2-skip-build: true # build both Debug and RelWithDebInfo for package - name: Build UI Base + working-directory: ${{ steps.configure-uibase.outputs.working-directory }} run: | cmake --build vsbuild --config Debug --target uibase-tests --verbose cmake --build vsbuild --config RelWithDebInfo --target uibase-tests --verbose - name: Test UI Base + working-directory: ${{ steps.configure-uibase.outputs.working-directory }} run: | ctest --test-dir vsbuild -C Debug --output-on-failure ctest --test-dir vsbuild -C RelWithDebInfo --output-on-failure - name: Install UI Base + working-directory: ${{ steps.configure-uibase.outputs.working-directory }} run: | cmake --install vsbuild --config Debug cmake --install vsbuild --config RelWithDebInfo @@ -59,11 +52,11 @@ jobs: # this tests that UI Base can be properly used as a CMake package - name: Test UI Base package run: | - cmake -B build . "-DCMAKE_PREFIX_PATH=${env:QT_ROOT_DIR}\msvc2019_64;..\..\install\lib\cmake\" + cmake -B build . "-DCMAKE_PREFIX_PATH=${env:QT_ROOT_DIR}\msvc2022_64;${{ github.workspace }}\install\lib\cmake\" cmake --build build --config Debug cmake --build build --config Release cmake --build build --config RelWithDebInfo - working-directory: tests/cmake + working-directory: ${{ steps.configure-uibase.outputs.working-directory }}/tests/cmake - name: Upload UI Base artifact uses: actions/upload-artifact@master diff --git a/CMakeLists.txt b/CMakeLists.txt index ec4792c4..065e6139 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,8 +37,8 @@ install(FILES DESTINATION lib/cmake/mo2-uibase ) -set(UIBASE_TESTING ${UIBASE_TESTING} CACHE BOOL "build tests for uibase") -if (UIBASE_TESTING) +set(BUILD_TESTING ${BUILD_TESTING} CACHE BOOL "build tests for uibase") +if (BUILD_TESTING) enable_testing() add_subdirectory(tests) endif() diff --git a/README.md b/README.md index ba220be2..b9abeaae 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ $env:VCPKG_ROOT = "C:\vcpkg" cmake --preset vs2022-windows "-DCMAKE_PREFIX_PATH=$env:QT_ROOT" ` -DCMAKE_INSTALL_PREFIX=install ` - -DUIBASE_TESTING=ON + -DBUILD_TESTING=ON # build uibase cmake --build vsbuild --config RelWithDebInfo @@ -29,7 +29,7 @@ ctest --test-dir vsbuild -C RelWithDebInfo --output-on-failure Check [`CMakePresets.json`](CMakePresets.json) for some predefined values. Extra options include: -- `UIBASE_TESTING` - if specified, build tests for UIBase, requires the VCPKG `testing` +- `BUILD_TESTING` - if specified, build tests for UIBase, requires the VCPKG `testing` feature to be enabled (enabled in the preset). ## How to use? From fc142fe5454175da66ed50294041661c01221d7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Capelle?= Date: Sun, 25 May 2025 13:45:10 +0200 Subject: [PATCH 06/12] Clean Github action. --- .github/workflows/build.yml | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d3aeffd4..60769fbd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,21 +8,10 @@ on: pull_request: types: [opened, synchronize, reopened] -env: - VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite" - jobs: build: runs-on: windows-2022 steps: - # https://learn.microsoft.com/en-us/vcpkg/consume/binary-caching-github-actions-cache - - name: Export GitHub Actions cache environment variables - uses: actions/github-script@v7 - with: - script: | - core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); - core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); - - name: Configure UIBase id: configure-uibase uses: ModOrganizer2/build-with-mob-action@dev/vcpkg From 9347a0817b7052bce35c03c0c679e17bfb0546eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Capelle?= Date: Sun, 25 May 2025 13:49:04 +0200 Subject: [PATCH 07/12] Add pre-commit hook. --- .pre-commit-config.yaml | 20 ++++++++++++++++++++ include/uibase/formatters.h | 2 +- include/uibase/game_features/igamefeatures.h | 2 +- 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..3103a1f1 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,20 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-merge-conflict + - id: check-case-conflict + - repo: https://github.com/pre-commit/mirrors-clang-format + rev: v19.1.5 + hooks: + - id: clang-format + 'types_or': [c++, c] + +ci: + autofix_commit_msg: "[pre-commit.ci] Auto fixes from pre-commit.com hooks." + autofix_prs: true + autoupdate_commit_msg: "[pre-commit.ci] Pre-commit autoupdate." + autoupdate_schedule: quarterly + submodules: false diff --git a/include/uibase/formatters.h b/include/uibase/formatters.h index 78ee90fd..870e01d4 100644 --- a/include/uibase/formatters.h +++ b/include/uibase/formatters.h @@ -3,4 +3,4 @@ #include "./formatters/enums.h" #include "./formatters/qt.h" #include "./formatters/random_access_containers.h" -#include "./formatters/strings.h" \ No newline at end of file +#include "./formatters/strings.h" diff --git a/include/uibase/game_features/igamefeatures.h b/include/uibase/game_features/igamefeatures.h index c625bfbf..2d89b3cc 100644 --- a/include/uibase/game_features/igamefeatures.h +++ b/include/uibase/game_features/igamefeatures.h @@ -163,4 +163,4 @@ class IGameFeatures } // namespace MOBase -#endif \ No newline at end of file +#endif From 12f9a0c6841b527a431beda1753b26d33169bf96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Capelle?= Date: Sun, 25 May 2025 14:45:14 +0200 Subject: [PATCH 08/12] Bump VCPKG registry baselines. --- include/uibase/ifiletree.h | 2 +- src/uibase_en.ts | 28 ++++++++++++++-------------- vcpkg.json | 6 +++--- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/include/uibase/ifiletree.h b/include/uibase/ifiletree.h index bf06d1e3..83781b28 100644 --- a/include/uibase/ifiletree.h +++ b/include/uibase/ifiletree.h @@ -598,7 +598,7 @@ class QDLLEXPORT IFileTree : public virtual FileTreeEntry */ QString pathTo(std::shared_ptr entry, QString sep = "\\") const { - return entry->pathFrom(astree()); + return entry->pathFrom(astree(), sep); } public: // Walk operations diff --git a/src/uibase_en.ts b/src/uibase_en.ts index 7f02320f..defc5452 100644 --- a/src/uibase_en.ts +++ b/src/uibase_en.ts @@ -179,7 +179,7 @@ - + Failed to save '%1', could not create a temporary file: %2 (error %3) Failed to save '{}', could not create a temporary file: {} (error {}) @@ -223,52 +223,52 @@ - + %1 B - + %1 KB - + %1 MB - + %1 GB - + %1 TB - + %1 B/s - + %1 KB/s - + %1 MB/s - + %1 GB/s - + %1 TB/s @@ -386,19 +386,19 @@ uibase - + h Time remaining hours - + m Time remaining minutes - + s Time remaining seconds diff --git a/vcpkg.json b/vcpkg.json index 6c1e8c9d..47779187 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -3,7 +3,7 @@ "overrides": [ { "name": "spdlog", - "version": "1.14.1" + "version": "1.15.3" } ], "features": { @@ -20,13 +20,13 @@ "default-registry": { "kind": "git", "repository": "https://github.com/Microsoft/vcpkg", - "baseline": "8ae59b5b1329a51875abc71d528da93d9c3e8972" + "baseline": "294f76666c3000630d828703e675814c05a4fd43" }, "registries": [ { "kind": "git", "repository": "https://github.com/ModOrganizer2/vcpkg-registry", - "baseline": "84ff92223433d101738a3c6cef96fa6ae6a6f302", + "baseline": "8beb2e0efa9c17dd6d17bb05288dd1e40727f673", "packages": ["mo2-cmake", "spdlog"] } ] From 35b3e4770cb7ef1be24ba9fe4893f4acb9665055 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Capelle?= Date: Sun, 25 May 2025 16:57:33 +0200 Subject: [PATCH 09/12] Update GH Action to use AZ Blob. --- .github/workflows/build.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 60769fbd..7ff992a8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,6 +8,9 @@ on: pull_request: types: [opened, synchronize, reopened] +env: + VCPKG_BINARY_SOURCES: clear;x-azblob,${{ vars.AZ_BLOB_VCPKG_URL }},${{ secrets.AZ_BLOB_SAS }},readwrite + jobs: build: runs-on: windows-2022 From cda06090b970da85bac9fa6d702d26820054c12b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Capelle?= Date: Sun, 25 May 2025 18:16:11 +0200 Subject: [PATCH 10/12] Add CMake build preset. --- CMakePresets.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CMakePresets.json b/CMakePresets.json index f0e338e3..62939333 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -62,5 +62,12 @@ "name": "vs2022-windows-standalone" } ], + "buildPresets": [ + { + "name": "vs2022-windows", + "resolvePackageReferences": "on", + "configurePreset": "vs2022-windows" + } + ], "version": 4 } From b1a0e7d6064db524f17537a6956ee147ef11840d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Capelle?= Date: Tue, 27 May 2025 22:30:43 +0200 Subject: [PATCH 11/12] Fix issue with invalidated iterator in ireplace_all. --- src/strings.cpp | 14 +++++++------- tests/test_strings.cpp | 5 +++++ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/strings.cpp b/src/strings.cpp index ef84fb04..768f6921 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -31,14 +31,14 @@ void ireplace_all(std::string& input, std::string_view search, { const auto search_length = static_cast(search.size()); const auto replace_length = replace.size(); - auto it = input.begin(); - while (input.end() - it >= search_length) { - const auto search_end = it + search_length; - if (iequals(std::string_view(it, search_end), search)) { - input.replace(it, search_end, replace); - it += static_cast(replace_length); + + std::size_t i = 0; + while (input.size() - i >= search_length) { + if (iequals(std::string_view(input).substr(i, search_length), search)) { + input.replace(i, search_length, replace); + i += replace_length; } else { - ++it; + ++i; } } } diff --git a/tests/test_strings.cpp b/tests/test_strings.cpp index 56e75c9b..0185f83a 100644 --- a/tests/test_strings.cpp +++ b/tests/test_strings.cpp @@ -32,6 +32,11 @@ TEST(StringsTest, IReplaceAll) ASSERT_EQ("replace a stuff with a stuff som", ireplace_all("replace some stuff with some stuff som", "some", "a")); ASSERT_EQ("1YYY3YYY2", ireplace_all("1aBc3AbC2", "abC", "YYY")); + + ASSERT_EQ( + "data path: C:/Users/USERNAME/AppData/Local/ModOrganizer/Starfield", + ireplace_all("data path: C:/Users/lords/AppData/Local/ModOrganizer/Starfield", + "/lords", "/USERNAME")); } // this is more a tests of the tests From 095caa0cab19013520a4c5b5996d504269d64332 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Capelle?= Date: Wed, 28 May 2025 14:02:13 +0200 Subject: [PATCH 12/12] Update Github action. --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7ff992a8..ea051889 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,7 +17,7 @@ jobs: steps: - name: Configure UIBase id: configure-uibase - uses: ModOrganizer2/build-with-mob-action@dev/vcpkg + uses: ModOrganizer2/build-with-mob-action@master with: # skip build because we are going to build both Debug and RelWithDebInfo here mo2-skip-build: true