diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index df9b592f..aa18166e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,118 +1,22 @@ +include: + - ".gitlab/ci/base_jobs.yml" + - ".gitlab/ci/build_jobs.yml" + - ".gitlab/ci/build_release_jobs.yml" + - ".gitlab/ci/check_jobs.yml" + stages: + # None Steam build for every commit - build + # Steam build for every commit + - build_steam + # Git release tag builds + - release_build + # Gitlab releases at: + # https://gitlab.com/kelteseth/ScreenPlay/-/releases + - release + # Checks for source code formattings - check -.base_windows_build: - before_script: - - python -m pip install -U pip wheel - - python -m pip install -r Tools/requirements.txt - - python Tools/setup.py - -.base_linux_build: - before_script: - # Otherwise libglib2 needs interaction - - export DEBIAN_FRONTEND=noninteractive - - apt update -y - - apt install libwayland-dev wayland-protocols curl wget zip unzip tar git pkg-config libxcb-* libfontconfig-dev apt-transport-https ca-certificates gnupg software-properties-common python3 python3-pip build-essential libgl1-mesa-dev mesa-common-dev lld ninja-build libxkbcommon-* libx11-dev xserver-xorg-dev xorg-dev -y - - wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null - - echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ focal-rc main' | tee -a /etc/apt/sources.list.d/kitware.list >/dev/null - - apt update -y - - apt install cmake -y - - python3 -m pip install -U pip - - python3 -m pip install -r Tools/requirements.txt - - python3 Tools/setup.py - -.base_osx_build: - before_script: - - pip3 install -U pip - - pip3 install -r Tools/requirements.txt - - python3 Tools/setup.py - -standalone_windows: - stage: build - extends: - - .base_windows_build - tags: - - windows10 - script: - - python Tools/build.py -type release -use-aqt -installer -deploy-version - artifacts: - expire_in: "2 weeks" - paths: - - build-x64-windows-release/bin/ - - build-x64-windows-release/ScreenPlay-Installer.exe - -standalone_osx: - stage: build - extends: - - .base_osx_build - tags: - - osx - script: - - python3 Tools/build.py -type release -use-aqt -deploy-version -sign_osx - artifacts: - expire_in: "2 weeks" - paths: - - build-64-osx-universal-release/bin/ - -standalone_linux: - stage: build - extends: - - .base_linux_build - image: - name: ubuntu:20.04 - tags: - - gitlab-org-docker - script: - - python3 Tools/build.py -type release -deploy-version -use-aqt -installer - artifacts: - expire_in: "4 weeks" - paths: - - build-x64-linux-release/bin/ - -steam_windows: - stage: build - extends: - - .base_windows_build - tags: - - windows10 - script: - - python Tools/build.py -type release -steam -use-aqt -deploy-version - artifacts: - expire_in: "2 weeks" - paths: - - build-x64-windows-release/bin/ - -steam_osx: - stage: build - extends: - - .base_osx_build - tags: - - osx - script: - - python3 Tools/build.py -type release -steam -use-aqt -deploy-version -sign_osx - artifacts: - expire_in: "2 weeks" - paths: - - build-64-osx-universal-release/bin/ - -formatting: - stage: check - allow_failure: true - image: - name: ubuntu:20.04 - tags: - - gitlab-org-docker - before_script: - - apt-get update -y - - apt-get install python3-pip python-is-python3 clang clang-format -y - script: - - python -m pip install -U pip wheel - - python -m pip install -U cmakelang - - cd Tools - - python clang_format.py - - python cmake_format.py - documentation: stage: .post script: diff --git a/.gitlab/ci/base_jobs.yml b/.gitlab/ci/base_jobs.yml new file mode 100644 index 00000000..512370b5 --- /dev/null +++ b/.gitlab/ci/base_jobs.yml @@ -0,0 +1,49 @@ +.base_windows_build: + dependencies: [] + before_script: + - python -m pip install -U pip wheel + - python -m pip install -r Tools/requirements.txt + - python Tools/setup.py + tags: + - windows10 + artifacts: + expire_in: "2 weeks" + paths: + - build-x64-windows-release/bin/ + - build-x64-windows-release/ScreenPlay-Installer.exe + +.base_linux_build: + dependencies: [] + before_script: + # Otherwise libglib2 needs interaction + - export DEBIAN_FRONTEND=noninteractive + - apt update -y + - apt install libwayland-dev wayland-protocols curl wget zip unzip tar git pkg-config libxcb-* libfontconfig-dev apt-transport-https ca-certificates gnupg software-properties-common python3 python3-pip build-essential libgl1-mesa-dev mesa-common-dev lld ninja-build libxkbcommon-* libx11-dev xserver-xorg-dev xorg-dev -y + - wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null + - echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ focal-rc main' | tee -a /etc/apt/sources.list.d/kitware.list >/dev/null + - apt update -y + - apt install cmake -y + - python3 -m pip install -U pip + - python3 -m pip install -r Tools/requirements.txt + - python3 Tools/setup.py + image: + name: ubuntu:20.04 + tags: + - gitlab-org-docker + artifacts: + expire_in: "4 weeks" + paths: + - build-x64-linux-release/bin/ + +.base_osx_build: + dependencies: [] + before_script: + - pip3 install -U pip + - pip3 install -r Tools/requirements.txt + - python3 Tools/setup.py + tags: + - osx + artifacts: + expire_in: "2 weeks" + paths: + - build-64-osx-universal-release/bin/ diff --git a/.gitlab/ci/build_jobs.yml b/.gitlab/ci/build_jobs.yml new file mode 100644 index 00000000..5a7821fb --- /dev/null +++ b/.gitlab/ci/build_jobs.yml @@ -0,0 +1,41 @@ +standalone_windows: + stage: build + extends: + - .base_windows_build + script: + - python Tools/build.py --type=release --use-aqt --installer --deploy-version + +standalone_osx: + stage: build + extends: + - .base_osx_build + script: + - python3 Tools/build.py --type=release --use-aqt --deploy-version --sign_osx + +standalone_linux: + stage: build + extends: + - .base_linux_build + script: + - python3 Tools/build.py --type=release --use-aqt --installer --deploy-version + +steam_windows: + stage: build_steam + extends: + - .base_windows_build + script: + - python Tools/build.py --type=release -steam --use-aqt --deploy-version + +steam_osx: + stage: build_steam + extends: + - .base_osx_build + script: + - python3 Tools/build.py --type=release -steam --use-aqt --deploy-version --sign_osx + +steam_linux: + stage: build_steam + extends: + - .base_linux_build + script: + - python3 Tools/build.py --type=release -steam --deploy-version --use-aqt --installer diff --git a/.gitlab/ci/build_release_jobs.yml b/.gitlab/ci/build_release_jobs.yml new file mode 100644 index 00000000..b24cdc06 --- /dev/null +++ b/.gitlab/ci/build_release_jobs.yml @@ -0,0 +1,78 @@ +steam_linux: + stage: release_build + extends: + - .base_linux_build + script: + - python3 Tools/build.py --type=release --steam --deploy-version --use-aqt --installer + rules: + - if: "$CI_COMMIT_TAG" + artifacts: + paths: + - build-x64-linux-release/ScreenPlay-$CI_COMMIT_TAG-x64-linux-release.zip + - build-x64-linux-release/ScreenPlay-$CI_COMMIT_TAG-x64-linux-release.zip.sha256.txt + +steam_windows: + stage: release_build + extends: + - .base_windows_build + script: + - python Tools/build.py --type=release --steam --use-aqt --deploy-version + rules: + - if: "$CI_COMMIT_TAG" + artifacts: + paths: + - build-x64-windows-release/ScreenPlay-$CI_COMMIT_TAG-x64-windows-release.zip + - build-x64-windows-release/ScreenPlay-$CI_COMMIT_TAG-x64-windows-release.zip.sha256.txt + +steam_osx: + stage: release_build + extends: + - .base_osx_build + script: + - python3 Tools/build.py --type=release --steam --use-aqt --deploy-version --sign_osx + rules: + - if: "$CI_COMMIT_TAG" + artifacts: + paths: + - build-64-osx-universal-release/ScreenPlay-$CI_COMMIT_TAG-64-osx-universal-release.zip + - build-64-osx-universal-release/ScreenPlay-$CI_COMMIT_TAG-64-osx-universal-release.zip.sha256.txt + +release_job: + stage: release + image: python:3.11 + dependencies: + - steam_linux + - steam_windows + - steam_osx + rules: + - if: "$CI_COMMIT_TAG" # Run this job when a tag is created + when: on_success # Only when all previous jobs succeed + script: + # 1. Combining sha256 files into a SHA512-SUMS.txt + - python3 Tools/create_sha512.py + # 2. Install dependencies and handle the folder + - apt update + - apt install -y sshpass ssh curl + - curl --location --output /usr/local/bin/release-cli "https://gitlab.com/api/v4/projects/gitlab-org%2Frelease-cli/packages/generic/release-cli/latest/release-cli-linux-amd64" + - chmod +x /usr/local/bin/release-cli + - ssh-keyscan 91.204.46.10 >> ~/.ssh/known_hosts + - sshpass -p $GETSP_PASSWORD ssh $GETSP_USERNAME@91.204.46.10 "rm -rf /getsp.de/httpdocs/releases/$CI_COMMIT_TAG; mkdir /getsp.de/httpdocs/releases/$CI_COMMIT_TAG;" + # 3. Upload files to the remote folder + - sshpass -p $GETSP_PASSWORD scp build-x64-linux-release/ScreenPlay-$CI_COMMIT_TAG-x64-linux-release.zip $GETSP_USERNAME@91.204.46.10:/getsp.de/httpdocs/releases/$CI_COMMIT_TAG/ + - sshpass -p $GETSP_PASSWORD scp build-x64-windows-release/ScreenPlay-$CI_COMMIT_TAG-x64-windows-release.zip $GETSP_USERNAME@91.204.46.10:/getsp.de/httpdocs/releases/$CI_COMMIT_TAG/ + - sshpass -p $GETSP_PASSWORD scp build-64-osx-universal-release/ScreenPlay-$CI_COMMIT_TAG-64-osx-universal-release.zip $GETSP_USERNAME@91.204.46.10:/getsp.de/httpdocs/releases/$CI_COMMIT_TAG/ + - sshpass -p $GETSP_PASSWORD scp SHA512-SUMS.txt $GETSP_USERNAME@91.204.46.10:/getsp.de/httpdocs/releases/$CI_COMMIT_TAG/ + release: + tag_name: $CI_COMMIT_TAG + name: "ScreenPlay $CI_COMMIT_TAG Released!" + description: "šŸŽ‰ A Wild ScreenPlay Release Appeared!" + assets: + links: + - name: šŸ§ Linux x64 build + url: "https://getsp.de/releases/$CI_COMMIT_TAG/ScreenPlay-$CI_COMMIT_TAG-x64-linux-release.zip" + - name: šŸŖŸ Windows x64 build + url: "https://getsp.de/releases/$CI_COMMIT_TAG/ScreenPlay-$CI_COMMIT_TAG-x64-windows-release.zip" + - name: šŸ OSX universal build + url: "https://getsp.de/releases/$CI_COMMIT_TAG/ScreenPlay-$CI_COMMIT_TAG-64-osx-universal-release.zip" + - name: ā„¹ļø SHA512-SUMS.txt + url: "https://getsp.de/releases/$CI_COMMIT_TAG/SHA512-SUMS.txt" diff --git a/.gitlab/ci/check_jobs.yml b/.gitlab/ci/check_jobs.yml new file mode 100644 index 00000000..f3890288 --- /dev/null +++ b/.gitlab/ci/check_jobs.yml @@ -0,0 +1,18 @@ +formatting: + dependencies: [] + stage: check + allow_failure: true + image: + name: ubuntu:23.10 + tags: + - gitlab-org-docker + before_script: + - apt-get update -y + - apt-get install python3-pip python-is-python3 clang clang-format -y + script: + - python -m pip install -U pip wheel --break-system-packages + - python -m pip install -U cmakelang --break-system-packages + - cd Tools + - python check_format_cmake.py --check + - python check_format_cpp.py --check + #- python check_format_qml.py --check diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 0ad99001..a6b91c44 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -28,7 +28,7 @@ "cwd": "${workspaceFolder}/Tools" }, "args": [ - "clang_format.py" + "check_format_cpp.py" ] }, { @@ -46,7 +46,7 @@ "cwd": "${workspaceFolder}/Tools" }, "args": [ - "cmake_format.py" + "check_format_cmake.py" ] }, { @@ -64,7 +64,7 @@ "cwd": "${workspaceFolder}/Tools" }, "args": [ - "qml_format.py" + "check_format_qml.py" ] }, { @@ -87,7 +87,7 @@ }, { "type": "process", - "label": "Export ScreenPlay release, with deploy and steam enabled", + "label": "Build ScreenPlay release, with deploy and steam enabled", "command": "python3", "windows": { "command": "python" @@ -102,16 +102,16 @@ "osx": { "args": [ "build.py", - "-type=release", - "-deploy-version", - "-steam" + "--type=release", + "--deploy-version", + "--steam" ] }, "args": [ "build.py", - "-type=release", - "-deploy-version", - "-steam" + "--type=release", + "--deploy-version", + "--steam" ] }, { diff --git a/CMake/CMakeLists.txt b/CMake/CMakeLists.txt index 124d6949..b1d75b0d 100644 --- a/CMake/CMakeLists.txt +++ b/CMake/CMakeLists.txt @@ -2,6 +2,7 @@ project(CMake) set(FILES CMakeVariables.h.in + GetProjectVersion.cmake GenerateCMakeVariableHeader.cmake CopyRecursive.cmake CreateIFWInstaller.cmake) diff --git a/CMake/CreateDmgInstaller.cmake b/CMake/CreateDmgInstaller.cmake new file mode 100644 index 00000000..15c87e64 --- /dev/null +++ b/CMake/CreateDmgInstaller.cmake @@ -0,0 +1,22 @@ +message(STATUS "[DMG INSTALLER ENABLED]: Configuring. This can take some time...") + +set(CPACK_GENERATOR "DragNDrop") +set(CPACK_DMG_FORMAT "UDBZ") +set(CPACK_DMG_VOLUME_NAME "ScreenPlay") +set(CPACK_SYSTEM_NAME "OSX") +set(CPACK_PACKAGE_ICON "${CMAKE_SOURCE_DIR}/ScreenPlay/assets/icons/app.ico") + +set(CPACK_COMPONENTS_GROUPING IGNORE) +set(CPACK_PACKAGE_NAME "ScreenPlay") +set(CPACK_PACKAGE_FILE_NAME "ScreenPlay-Installer") +set(CPACK_PACKAGE_VENDOR "Elias Steurer") +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PROJECT_DESCRIPTION}") +set(CPACK_PACKAGE_DIRECTORY "${CMAKE_BINARY_DIR}") + +include(CPack) + +# Install all files from /bin +install( + DIRECTORY "${CMAKE_BINARY_DIR}/bin/" + COMPONENT ScreenPlay + DESTINATION "./") \ No newline at end of file diff --git a/CMake/GetProjectVersion.cmake b/CMake/GetProjectVersion.cmake new file mode 100644 index 00000000..02f43d24 --- /dev/null +++ b/CMake/GetProjectVersion.cmake @@ -0,0 +1,33 @@ +# Function: get_project_version +# +# Description: +# Fetches the project version from the latest Git tag. If Git is not found or +# the current directory is not a Git repository, it defaults to "0.0.0". +# +# Parameters: +# - VERSION_VAR: The name of the variable in which the fetched or default version will be stored. +# +# Example Usage: +# get_project_version(PROJECT_VERSION) +# message(STATUS "Version: ${PROJECT_VERSION}") +# +function(get_project_version VERSION_VAR) + find_package(Git) + if(GIT_FOUND) + execute_process( + COMMAND ${GIT_EXECUTABLE} describe --tags --always + OUTPUT_VARIABLE GIT_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + ) + + message(STATUS "Parsing git tag: ${GIT_VERSION}") + string(REPLACE "v" "" STRIPPED_VERSION "${GIT_VERSION}") # Remove the 'v' prefix + string(REPLACE "-" ";" VERSION_LIST ${STRIPPED_VERSION}) + list(GET VERSION_LIST 0 VERSION_STRING) + + set(${VERSION_VAR} ${VERSION_STRING} PARENT_SCOPE) + else() + set(${VERSION_VAR} "0.0.0" PARENT_SCOPE) + endif() +endfunction() diff --git a/CMakeLists.txt b/CMakeLists.txt index 853bb589..afcad827 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,12 @@ cmake_minimum_required(VERSION 3.23.0) +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake" ${CMAKE_MODULE_PATH}) +include(GetProjectVersion) +get_project_version(PROJECT_VERSION) + project( ScreenPlay - VERSION 0.15.0 + VERSION ${PROJECT_VERSION} DESCRIPTION "Modern, Cross Plattform, Live Wallpaper, Widgets and AppDrawer!" HOMEPAGE_URL "https://screen-play.app/" LANGUAGES CXX) @@ -146,23 +150,28 @@ if(WIN32) add_subdirectory(ScreenPlaySysInfo) endif() -if(${SCREENPLAY_INSTALLER} AND NOT APPLE) - include(${CMAKE_CURRENT_SOURCE_DIR}/CMake/CreateIFWInstaller.cmake) +if(${SCREENPLAY_INSTALLER}) + if(APPLE) + include(${CMAKE_CURRENT_SOURCE_DIR}/CMake/CreateDmgInstaller.cmake) + else() + include(${CMAKE_CURRENT_SOURCE_DIR}/CMake/CreateIFWInstaller.cmake) + endif() endif() -message(STATUS "[CPP DEFINE] DEPLOY_VERSION = ${DEPLOY_VERSION}") -message(STATUS "[CPP DEFINE] SOURCE_DIR = ${CMAKE_CURRENT_SOURCE_DIR}") -message(STATUS "[CPP DEFINE] BUILD_DATE = ${BUILD_DATE}") -message(STATUS "[DEFINE] BUILD_TYPE = ${CMAKE_BUILD_TYPE}") -message(STATUS "[DEFINE] GIT_COMMIT_HASH = ${GIT_COMMIT_HASH}") -message(STATUS "[OPTION] SCREENPLAY_DEPLOY = ${SCREENPLAY_DEPLOY}") -message(STATUS "[OPTION] SCREENPLAY_INSTALLER = ${SCREENPLAY_INSTALLER}") -message(STATUS "[OPTION] SCREENPLAY_STEAM = ${SCREENPLAY_STEAM}") -message(STATUS "[OPTION] SCREENPLAY_TESTS = ${SCREENPLAY_TESTS}") +message(STATUS "[PROJECT] PROJECT_VERSION = ${PROJECT_VERSION}") +message(STATUS "[PROJECT] CMAKE_VERSION = ${CMAKE_VERSION}") message(STATUS "[PROJECT] SCREENPLAY_QML_MODULES_PATH = ${SCREENPLAY_QML_MODULES_PATH}") message(STATUS "[PROJECT] CMAKE_TOOLCHAIN_FILE = ${CMAKE_TOOLCHAIN_FILE}") message(STATUS "[PROJECT] VCPKG_PATH = ${VCPKG_PATH}") message(STATUS "[PROJECT] CMAKE_MODULE_PATH = ${CMAKE_MODULE_PATH}") message(STATUS "[PROJECT] VCPKG_TARGET_TRIPLET = ${VCPKG_TARGET_TRIPLET}") message(STATUS "[PROJECT] CMAKE_PREFIX_PATH = ${CMAKE_PREFIX_PATH}") -message(STATUS "[PROJECT] CMAKE_VERSION = ${CMAKE_VERSION}") +message(STATUS "[OPTION] SCREENPLAY_DEPLOY = ${SCREENPLAY_DEPLOY}") +message(STATUS "[OPTION] SCREENPLAY_INSTALLER = ${SCREENPLAY_INSTALLER}") +message(STATUS "[OPTION] SCREENPLAY_STEAM = ${SCREENPLAY_STEAM}") +message(STATUS "[OPTION] SCREENPLAY_TESTS = ${SCREENPLAY_TESTS}") +message(STATUS "[DEFINE] BUILD_TYPE = ${CMAKE_BUILD_TYPE}") +message(STATUS "[DEFINE] GIT_COMMIT_HASH = ${GIT_COMMIT_HASH}") +message(STATUS "[CPP DEFINE] DEPLOY_VERSION = ${DEPLOY_VERSION}") +message(STATUS "[CPP DEFINE] SOURCE_DIR = ${CMAKE_CURRENT_SOURCE_DIR}") +message(STATUS "[CPP DEFINE] BUILD_DATE = ${BUILD_DATE}") diff --git a/Content/wallpaper_qml/main.qml b/Content/wallpaper_qml/main.qml index 475be5a1..92e21a65 100644 --- a/Content/wallpaper_qml/main.qml +++ b/Content/wallpaper_qml/main.qml @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: BSD-3-Clause import QtQuick import QtQuick.Layouts diff --git a/Content/wallpaper_qml_particles/main.qml b/Content/wallpaper_qml_particles/main.qml index 35febbda..9f2b561f 100644 --- a/Content/wallpaper_qml_particles/main.qml +++ b/Content/wallpaper_qml_particles/main.qml @@ -42,19 +42,19 @@ Item { anchors.fill: parent hoverEnabled: true Component.onCompleted: { - attractor.pointX = parent.width * .5 - attractor.pointY = 0 + attractor.pointX = parent.width * .5; + attractor.pointY = 0; } onPressed: { - attractor.enabled = true + attractor.enabled = true; } onPositionChanged: { - attractor.pointX = mouseX - attractor.pointY = mouseY + attractor.pointX = mouseX; + attractor.pointY = mouseY; } onReleased: { - attractor.enabled = false + attractor.enabled = false; } } @@ -119,7 +119,7 @@ Item { bottom: parent.bottom bottomMargin: -width * .65 } - SequentialAnimation on opacity { + SequentialAnimation on opacity { loops: Animation.Infinite OpacityAnimator { diff --git a/Content/widget_digital_clock/main.qml b/Content/widget_digital_clock/main.qml index 42fab09e..8af90611 100644 --- a/Content/widget_digital_clock/main.qml +++ b/Content/widget_digital_clock/main.qml @@ -8,32 +8,31 @@ Item { implicitHeight: 100 function timeChanged() { - var date = new Date - var hours = "" - var minutes = "" - var seconds = "" + var date = new Date; + var hours = ""; + var minutes = ""; + var seconds = ""; if (date.getHours() < 10) { - hours = "0" + date.getHours().toString() + hours = "0" + date.getHours().toString(); } else { - hours = date.getHours().toString() + hours = date.getHours().toString(); } if (date.getMinutes() < 10) { - minutes = "0" + date.getMinutes().toString() + minutes = "0" + date.getMinutes().toString(); } else { - minutes = date.getMinutes().toString() + minutes = date.getMinutes().toString(); } if (date.getSeconds() < 10) { - seconds = "0" + date.getSeconds().toString() + seconds = "0" + date.getSeconds().toString(); } else { - seconds = date.getSeconds().toString() + seconds = date.getSeconds().toString(); } - var days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'] - var months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'] - var day = days[date.getDay()] - var month = months[date.getMonth()] - txtClock.text = hours + ":" + minutes + ":" + seconds - txtDate.text = day + ", " + date.getDay( - ) + " " + month + ", " + date.getFullYear() + var days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; + var months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; + var day = days[date.getDay()]; + var month = months[date.getMonth()]; + txtClock.text = hours + ":" + minutes + ":" + seconds; + txtDate.text = day + ", " + date.getDay() + " " + month + ", " + date.getFullYear(); } Timer { diff --git a/Content/widget_rss_guardian_news/PostDelegate.qml b/Content/widget_rss_guardian_news/PostDelegate.qml index 5e3b1d61..83b46b1e 100644 --- a/Content/widget_rss_guardian_news/PostDelegate.qml +++ b/Content/widget_rss_guardian_news/PostDelegate.qml @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: BSD-3-Clause import QtQuick import QtQuick.Layouts @@ -17,16 +16,16 @@ Item { property string link property string mediaContent onMediaContentChanged: { - print("src") - const src = parseItem(model.mediaContent, 'url="', '"') - print("src", src) + print("src"); + const src = parseItem(model.mediaContent, 'url="', '"'); + print("src", src); //img.source = src; } function parseItem(raw, startTag, endTag) { - var startIdx = raw.indexOf(startTag) + startTag.length - var endIdx = raw.indexOf(endTag, startIdx) - return raw.substring(startIdx, endIdx) + var startIdx = raw.indexOf(startTag) + startTag.length; + var endIdx = raw.indexOf(endTag, startIdx); + return raw.substring(startIdx, endIdx); } RowLayout { @@ -49,8 +48,8 @@ Item { MouseArea { anchors.fill: parent onClicked: { - print(model.category) - print(model.mediaContent) + print(model.category); + print(model.mediaContent); //Qt.openUrlExternally(model.link); } } diff --git a/Content/widget_rss_guardian_news/main.qml b/Content/widget_rss_guardian_news/main.qml index e54e55e4..f86de527 100644 --- a/Content/widget_rss_guardian_news/main.qml +++ b/Content/widget_rss_guardian_news/main.qml @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: BSD-3-Clause import QtQuick import QtQuick.Controls @@ -18,7 +17,7 @@ Item { query: "/rss/channel/item" onStatusChanged: { if (status === XmlListModel.Error) { - console.log("Error: " + errorString) + console.log("Error: " + errorString); } } diff --git a/Content/widget_rss_hackernews/PostDelegate.qml b/Content/widget_rss_hackernews/PostDelegate.qml index 275823d5..badb4bbc 100644 --- a/Content/widget_rss_hackernews/PostDelegate.qml +++ b/Content/widget_rss_hackernews/PostDelegate.qml @@ -12,41 +12,38 @@ Item { property string pubDate property string pubDateFormatted onPubDateChanged: { - var date = new Date(pubDate) - root.pubDateFormatted = date.toLocaleDateString( - Qt.locale(), - "ddd, dd MMM yyyy") + ' ' + date.toLocaleTimeString( - Qt.locale(), "HH:mm:ss") + var date = new Date(pubDate); + root.pubDateFormatted = date.toLocaleDateString(Qt.locale(), "ddd, dd MMM yyyy") + ' ' + date.toLocaleTimeString(Qt.locale(), "HH:mm:ss"); } property string description onDescriptionChanged: { - print("description") + print("description"); // See https://hnrss.org/frontpage content // We need to manually parse it here to get the points and comments - points = parsePoints(description) - commentCount = parseCommentCount(description) - print(points, commentCount) + points = parsePoints(description); + commentCount = parseCommentCount(description); + print(points, commentCount); } function parseCommentCount(raw) { - var commentPrefix = "

# Comments: " - var commentSuffix = "

" - var startIdx = raw.indexOf(commentPrefix) + var commentPrefix = "

# Comments: "; + var commentSuffix = "

"; + var startIdx = raw.indexOf(commentPrefix); if (startIdx === -1) - return "N/A" // return "N/A" if comment count is not found in the description - startIdx += commentPrefix.length - var endIdx = raw.indexOf(commentSuffix, startIdx) - return raw.substring(startIdx, endIdx) + return "N/A"; // return "N/A" if comment count is not found in the description + startIdx += commentPrefix.length; + var endIdx = raw.indexOf(commentSuffix, startIdx); + return raw.substring(startIdx, endIdx); } function parsePoints(raw) { - var pointsPrefix = "

Points: " - var pointsSuffix = "

" - var startIdx = raw.indexOf(pointsPrefix) + var pointsPrefix = "

Points: "; + var pointsSuffix = "

"; + var startIdx = raw.indexOf(pointsPrefix); if (startIdx === -1) - return "N/A" // return "N/A" if points are not found in the description - startIdx += pointsPrefix.length - var endIdx = raw.indexOf(pointsSuffix, startIdx) - return raw.substring(startIdx, endIdx) + return "N/A"; // return "N/A" if points are not found in the description + startIdx += pointsPrefix.length; + var endIdx = raw.indexOf(pointsSuffix, startIdx); + return raw.substring(startIdx, endIdx); } RowLayout { id: wrapper @@ -68,15 +65,14 @@ Item { anchors.fill: parent cursorShape: Qt.PointingHandCursor onClicked: { - Qt.openUrlExternally(model.link) + Qt.openUrlExternally(model.link); } } } Text { id: descriptionText - text: root.points + " Points ā€¢ " + root.commentCount - + " Comments šŸ”— " + "ā€¢ Published: " + root.pubDateFormatted + text: root.points + " Points ā€¢ " + root.commentCount + " Comments šŸ”— " + "ā€¢ Published: " + root.pubDateFormatted wrapMode: Text.WordWrap font.pointSize: 10 opacity: .7 @@ -85,7 +81,7 @@ Item { anchors.fill: parent cursorShape: Qt.PointingHandCursor onClicked: { - Qt.openUrlExternally(model.commentsLink) + Qt.openUrlExternally(model.commentsLink); } } } diff --git a/Content/widget_rss_hackernews/main.qml b/Content/widget_rss_hackernews/main.qml index 87708c2c..99ddc3a8 100644 --- a/Content/widget_rss_hackernews/main.qml +++ b/Content/widget_rss_hackernews/main.qml @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: BSD-3-Clause import QtQuick import QtQuick.Layouts @@ -44,7 +43,7 @@ Item { } } onActivated: { - rssModel.source = combo.currentValue + rssModel.source = combo.currentValue; } } ToolButton { @@ -79,10 +78,10 @@ Item { source: combo.currentValue query: "/rss/channel/item" function load() { - print(":load") - var tempSource = rssModel.source - rssModel.source = "" - rssModel.source = tempSource + print(":load"); + var tempSource = rssModel.source; + rssModel.source = ""; + rssModel.source = tempSource; } XmlListModelRole { diff --git a/Content/widget_system_stats/main.qml b/Content/widget_system_stats/main.qml index abe23e9a..ec5fe20e 100644 --- a/Content/widget_system_stats/main.qml +++ b/Content/widget_system_stats/main.qml @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: BSD-3-Clause import QtQuick import QtQuick.Layouts @@ -28,11 +27,11 @@ Item { } function stringListToString(list) { - let out = "" + let out = ""; for (var i = 0; i < list.length; i++) { - out += "\n" + list[i] + out += "\n" + list[i]; } - return out + return out; } RowLayout { @@ -57,8 +56,7 @@ Item { } } Text { - text: root.stringListToString( - ipAddress.privateIpV4AddressList) + text: root.stringListToString(ipAddress.privateIpV4AddressList) color: root.accentColor font { pointSize: 16 @@ -66,8 +64,7 @@ Item { } } Text { - text: root.stringListToString( - ipAddress.privateIpV6AddressList) + text: root.stringListToString(ipAddress.privateIpV6AddressList) color: root.accentColor font { pointSize: 16 diff --git a/Content/widget_weather/main.qml b/Content/widget_weather/main.qml index 4f934ada..42a061eb 100644 --- a/Content/widget_weather/main.qml +++ b/Content/widget_weather/main.qml @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: BSD-3-Clause import QtQuick import QtQuick.Layouts @@ -20,56 +19,57 @@ Item { id: weather city: "Friedrichshafen" onReady: { - rp.model = weather.days + rp.model = weather.days; // Qt bug https://bugreports.qt.io/browse/QTBUG-105137 - test() + test(); } } - function test() {} + function test() { + } function mapWeatherCode(code) { - const weather_time = "" + const weather_time = ""; // or "-day", "-night" - const weather_prefix = "wi" + weather_time + "-" + const weather_prefix = "wi" + weather_time + "-"; // https://open-meteo.com/en/docs // WMO Weather interpretation codes (WW) // to https://erikflowers.github.io/weather-icons/ switch (code) { case 0: - return weather_prefix + "day-sunny" + return weather_prefix + "day-sunny"; case 1: case 2: case 3: - return weather_prefix + "cloud" + return weather_prefix + "cloud"; case 45: case 48: - return weather_prefix + "day-sunny" + return weather_prefix + "day-sunny"; case 51: case 53: case 55: - return weather_prefix + "rain-mix" + return weather_prefix + "rain-mix"; case 61: case 63: case 65: - return weather_prefix + "rain-mix" + return weather_prefix + "rain-mix"; case 71: case 73: case 75: - return weather_prefix + "snow" + return weather_prefix + "snow"; case 77: - return weather_prefix + "snow" + return weather_prefix + "snow"; case 80: case 81: case 82: - return weather_prefix + "snow" + return weather_prefix + "snow"; case 85: case 86: - return weather_prefix + "snow" + return weather_prefix + "snow"; case 95: - return weather_prefix + "thunderstorm" + return weather_prefix + "thunderstorm"; case 96: case 99: - return weather_prefix + "storm-showers" + return weather_prefix + "storm-showers"; } } @@ -89,9 +89,7 @@ Item { Layout.alignment: Qt.AlignCenter horizontalAlignment: Text.AlignHCenter color: Material.primaryTextColor - text: "longtitude: " + weather.longtitude + " - latitude: " - + weather.latitude + " - elevation: " + weather.elevation - + "m - population: " + weather.population + text: "longtitude: " + weather.longtitude + " - latitude: " + weather.latitude + " - elevation: " + weather.elevation + "m - population: " + weather.population } RowLayout { @@ -129,8 +127,7 @@ Item { } Layout.alignment: Qt.AlignCenter horizontalAlignment: Image.AlignHCenter - source: "qrc:/qml/ScreenPlayWeather/assets/icons/" + root.mapWeatherCode( - weatherCode) + ".svg" + source: "qrc:/qml/ScreenPlayWeather/assets/icons/" + root.mapWeatherCode(weatherCode) + ".svg" } TextItem { text: "Weather Code" diff --git a/Content/widget_xkcd/main.qml b/Content/widget_xkcd/main.qml index 377b6706..917c0cf0 100644 --- a/Content/widget_xkcd/main.qml +++ b/Content/widget_xkcd/main.qml @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: BSD-3-Clause import QtQuick import QtQuick.Controls @@ -15,27 +14,27 @@ Item { property int defaultHeight: 200 function request(url, callback) { - var xhr = new XMLHttpRequest() + var xhr = new XMLHttpRequest(); xhr.onreadystatechange = (function (myxhr) { - return function () { - if (myxhr.readyState === 4) - callback(myxhr) - } - })(xhr) - xhr.open('GET', url) - xhr.send('') + return function () { + if (myxhr.readyState === 4) + callback(myxhr); + }; + })(xhr); + xhr.open('GET', url); + xhr.send(''); } Component.onCompleted: { request("http://xkcd.com/info.0.json", function (o) { - if (o.status === 200) { - var d = eval('new Object(' + o.responseText + ')') - console.log(o.responseText) - img.source = d.img - } else { - console.log("Some error has occurred") - } - }) + if (o.status === 200) { + var d = eval('new Object(' + o.responseText + ')'); + console.log(o.responseText); + img.source = d.img; + } else { + console.log("Some error has occurred"); + } + }); } Image { @@ -45,22 +44,22 @@ Item { property size imgSize: Qt.size(root.defaultWidth, defaultHeight) onStatusChanged: { if (img.status !== Image.Ready) - return + return; if (img.sourceSize.width === 0 || img.sourceSize.height === 0) - return - root.implicitWidth = img.sourceSize.width - root.implicitHeight = img.sourceSize.height - print(img.status, img.sourceSize.width, img.sourceSize.height) - img.imgSize = Qt.size(img.sourceSize.width, img.sourceSize.height) - print("img.size", img.imgSize) + return; + root.implicitWidth = img.sourceSize.width; + root.implicitHeight = img.sourceSize.height; + print(img.status, img.sourceSize.width, img.sourceSize.height); + img.imgSize = Qt.size(img.sourceSize.width, img.sourceSize.height); + print("img.size", img.imgSize); } } MouseArea { anchors.fill: parent onClicked: { - root.state = root.state === "expanded" ? "normal" : "expanded" - print(root.state, root.implicitHeight, root.implicitWidth) + root.state = root.state === "expanded" ? "normal" : "expanded"; + print(root.state, root.implicitHeight, root.implicitWidth); } } diff --git a/Content/widget_year_count_down/main.qml b/Content/widget_year_count_down/main.qml index dfddb45e..39fab9d4 100644 --- a/Content/widget_year_count_down/main.qml +++ b/Content/widget_year_count_down/main.qml @@ -11,17 +11,9 @@ Item { implicitWidth: 240 implicitHeight: 120 property int totalHours: 24 - property int remainingHours: Math.max(0, Math.floor( - (new Date().setHours( - 24, 0, 0, - 0) - new Date()) / 3600000)) - property int totalDays: new Date(new Date().getFullYear() + 1, 0, - 1) - new Date() / (24 * 60 * 60 * 1000) - property int remainingDays: Math.max( - 0, Math.floor( - (new Date(new Date().getFullYear() + 1, - 0, - 1) - new Date()) / (24 * 60 * 60 * 1000))) + property int remainingHours: Math.max(0, Math.floor((new Date().setHours(24, 0, 0, 0) - new Date()) / 3600000)) + property int totalDays: new Date(new Date().getFullYear() + 1, 0, 1) - new Date() / (24 * 60 * 60 * 1000) + property int remainingDays: Math.max(0, Math.floor((new Date(new Date().getFullYear() + 1, 0, 1) - new Date()) / (24 * 60 * 60 * 1000))) Material.theme: Material.Dark Material.accent: Material.DeepOrange @@ -50,11 +42,7 @@ Item { running: true repeat: true onTriggered: { - remainingHours = Math.max( - 0, - Math.floor((new Date().setHours( - 24, 0, 0, - 0) - new Date()) / 3600000)) + remainingHours = Math.max(0, Math.floor((new Date().setHours(24, 0, 0, 0) - new Date()) / 3600000)); } } } @@ -81,11 +69,7 @@ Item { running: true repeat: true onTriggered: { - remainingDays = Math.max(0, - Math.floor((new Date(new Date().getFullYear( - ) + 1, - 0, 1) - - new Date()) / (24 * 60 * 60 * 1000))) + remainingDays = Math.max(0, Math.floor((new Date(new Date().getFullYear() + 1, 0, 1) - new Date()) / (24 * 60 * 60 * 1000))); } } } diff --git a/ScreenPlay/CMakeLists.txt b/ScreenPlay/CMakeLists.txt index fdafccf0..d2842184 100644 --- a/ScreenPlay/CMakeLists.txt +++ b/ScreenPlay/CMakeLists.txt @@ -138,6 +138,7 @@ set(RESOURCES assets/icons/icon_close.svg assets/icons/icon_code.svg assets/icons/icon_community.svg + assets/icons/icon_contains_audio.svg assets/icons/icon_delete.svg assets/icons/icon_document.svg assets/icons/icon_done.svg @@ -152,7 +153,6 @@ set(RESOURCES assets/icons/icon_installed.svg assets/icons/icon_launch.svg assets/icons/icon_minimize.svg - assets/icons/icon_contains_audio.svg assets/icons/icon_movie.svg assets/icons/icon_new_releases.svg assets/icons/icon_open_in_new.svg diff --git a/ScreenPlay/inc/public/ScreenPlay/settings.h b/ScreenPlay/inc/public/ScreenPlay/settings.h index 6c6cbd97..85edc6a4 100644 --- a/ScreenPlay/inc/public/ScreenPlay/settings.h +++ b/ScreenPlay/inc/public/ScreenPlay/settings.h @@ -470,7 +470,7 @@ private: bool m_checkWallpaperVisible { false }; bool m_silentStart { false }; bool m_anonymousTelemetry { true }; - bool m_showDefaultContent { true }; + bool m_showDefaultContent { false }; QString m_decoder; ScreenPlay::FillMode::FillMode m_videoFillMode { ScreenPlay::FillMode::FillMode::Cover }; diff --git a/ScreenPlay/main.qml b/ScreenPlay/main.qml index 803be4f3..4ec06b04 100644 --- a/ScreenPlay/main.qml +++ b/ScreenPlay/main.qml @@ -65,7 +65,7 @@ ApplicationWindow { screenSize: Qt.size(root.width, root.height) domain: "app.screen-play.app" debug: false - enabled: App.settings.anonymousTelemetry + enabled: false } // Partial workaround for diff --git a/ScreenPlay/qml/Installed/ScreenPlayItem.qml b/ScreenPlay/qml/Installed/ScreenPlayItem.qml index be8aa23d..f22a4701 100644 --- a/ScreenPlay/qml/Installed/ScreenPlayItem.qml +++ b/ScreenPlay/qml/Installed/ScreenPlayItem.qml @@ -175,7 +175,6 @@ Item { } } - Image { id: icnType diff --git a/ScreenPlay/qml/Installed/Sidebar.qml b/ScreenPlay/qml/Installed/Sidebar.qml index a9bb26ea..96ce53cc 100644 --- a/ScreenPlay/qml/Installed/Sidebar.qml +++ b/ScreenPlay/qml/Installed/Sidebar.qml @@ -43,7 +43,7 @@ Item { const item = App.installedListModel.get(root.contentFolderName); txtHeadline.text = item.m_title; const previewGiFilePath = Qt.resolvedUrl(item.m_absoluteStoragePath + "/" + item.m_previewGIF); - const previewImageFilePath = Qt.resolvedUrl( item.m_absoluteStoragePath + "/" + item.m_preview); + const previewImageFilePath = Qt.resolvedUrl(item.m_absoluteStoragePath + "/" + item.m_preview); root.hasPreviewGif = App.util.fileExists(previewGiFilePath); if (hasPreviewGif) { animatedImagePreview.source = previewGiFilePath; diff --git a/ScreenPlay/qml/Settings/Settings.qml b/ScreenPlay/qml/Settings/Settings.qml index 4f02b98a..6e540746 100644 --- a/ScreenPlay/qml/Settings/Settings.qml +++ b/ScreenPlay/qml/Settings/Settings.qml @@ -82,7 +82,7 @@ Item { isChecked: App.settings.showDefaultContent onCheckboxChanged: function (checked) { App.settings.setShowDefaultContent(checked); - App.installedListModel.reset() + App.installedListModel.reset(); } } diff --git a/ScreenPlaySDK/src/screenplaysdk.cpp b/ScreenPlaySDK/src/screenplaysdk.cpp index 20553e18..4caec706 100644 --- a/ScreenPlaySDK/src/screenplaysdk.cpp +++ b/ScreenPlaySDK/src/screenplaysdk.cpp @@ -186,20 +186,19 @@ void ScreenPlaySDK::ScreenPlaySDK::redirectMessageOutputToMainWindow(QtMsgType t // Also redirect to regular output if we debug // wallpaper or widgets directly - switch (type) - { + switch (type) { case QtDebugMsg: - qDebug() << msg; + qDebug() << msg; break; case QtWarningMsg: - qWarning() << msg; + qWarning() << msg; break; case QtCriticalMsg: case QtFatalMsg: - qCritical() << msg; + qCritical() << msg; break; case QtInfoMsg: - qInfo() << msg; + qInfo() << msg; break; default: break; diff --git a/ScreenPlayUtil/src/projectfile.cpp b/ScreenPlayUtil/src/projectfile.cpp index 401fcffa..d0e899bd 100644 --- a/ScreenPlayUtil/src/projectfile.cpp +++ b/ScreenPlayUtil/src/projectfile.cpp @@ -27,9 +27,9 @@ bool ProjectFile::init() return false; file = obj.value("file").toString(); - QFileInfo fileInfo(folder.path() + "/"+ file); - if(!fileInfo.exists()){ - qCritical() << "Requested file:" << fileInfo.absoluteFilePath() << "does not exist!"; + QFileInfo fileInfo(folder.path() + "/" + file); + if (!fileInfo.exists()) { + qCritical() << "Requested file:" << fileInfo.absoluteFilePath() << "does not exist!"; return false; } @@ -107,7 +107,7 @@ bool ProjectFile::init() } } - if (type == ScreenPlay::InstalledType::InstalledType::VideoWallpaper){ + if (type == ScreenPlay::InstalledType::InstalledType::VideoWallpaper) { QFileInfo audioFile(folder.absolutePath() + "/audio.mp3"); containsAudio = audioFile.exists(); } diff --git a/ScreenPlayWallpaper/qml/MultimediaView.qml b/ScreenPlayWallpaper/qml/MultimediaView.qml index 49101516..592462a7 100644 --- a/ScreenPlayWallpaper/qml/MultimediaView.qml +++ b/ScreenPlayWallpaper/qml/MultimediaView.qml @@ -49,7 +49,7 @@ Item { onPlaybackStateChanged: { if (mediaPlayer.playbackState == MediaPlayer.PlayingState && !fadeInDone) { fadeInDone = true; - startTimer.start() + startTimer.start(); } } loops: root.loops ? MediaPlayer.Infinite : 1 @@ -72,8 +72,7 @@ Item { id: pauseTimer interval: 100 onTriggered: { - mediaPlayer.pause() - + mediaPlayer.pause(); } } Connections { @@ -96,12 +95,12 @@ Item { } function onVisualsPausedChanged(visualsPaused) { - if(!Wallpaper.isPlaying) - return - if(visualsPaused) - pauseTimer.start() + if (!Wallpaper.isPlaying) + return; + if (visualsPaused) + pauseTimer.start(); else - mediaPlayer.play() + mediaPlayer.play(); } target: Wallpaper diff --git a/ScreenPlayWallpaper/src/basewindow.cpp b/ScreenPlayWallpaper/src/basewindow.cpp index b4119343..67231f16 100644 --- a/ScreenPlayWallpaper/src/basewindow.cpp +++ b/ScreenPlayWallpaper/src/basewindow.cpp @@ -60,8 +60,8 @@ ScreenPlay::WallpaperExitCode BaseWindow::setup() // We do not yet have implemented continue playing the audio.mp3 yet // so disable the checkWallpaperVisible for now - if(checkWallpaperVisible()){ - if(projectFile.containsAudio){ + if (checkWallpaperVisible()) { + if (projectFile.containsAudio) { qInfo() << "Disable wallpaper visible check, because it contains audio."; setCheckWallpaperVisible(false); } diff --git a/ScreenPlayWidget/main.cpp b/ScreenPlayWidget/main.cpp index 0445f60e..cffc4841 100644 --- a/ScreenPlayWidget/main.cpp +++ b/ScreenPlayWidget/main.cpp @@ -26,7 +26,7 @@ int main(int argc, char* argv[]) QtWebEngineQuick::initialize(); #if defined(Q_OS_WIN) - // Workaround for Qt 6.5.1 crash https://bugreports.qt.io/browse/QTBUG-113832 + // Workaround for Qt 6.5.1 crash https://bugreports.qt.io/browse/QTBUG-113832 qputenv("QT_DISABLE_HW_TEXTURES_CONVERSION", "1"); qputenv("QT_MEDIA_BACKEND", "ffmpeg"); #endif @@ -55,8 +55,8 @@ int main(int argc, char* argv[]) // Lets center the widget const auto* screen = QGuiApplication::screens().at(0); - const int offset = - 200; - QPoint center((screen->size().width() / 2) + offset, (screen->size().height() / 2)+offset); + const int offset = -200; + QPoint center((screen->size().width() / 2) + offset, (screen->size().height() / 2) + offset); WidgetWindow spwmw(projectPath, "appid", diff --git a/Tools/build.py b/Tools/build.py index bb392231..7f312a90 100755 --- a/Tools/build.py +++ b/Tools/build.py @@ -8,10 +8,12 @@ import argparse import time import zipfile import defines +from build_result import BuildResult +from build_config import BuildConfig from typing import Tuple from pathlib import Path import macos_sign -from util import sha256, cd_repo_root_path,repo_root_path, zipdir, run, get_vs_env_dict +from util import sha256, cd_repo_root_path, repo_root_path, zipdir, run, get_vs_env_dict, get_latest_git_tag, parse_semver, semver_to_string from sys import stdout stdout.reconfigure(encoding='utf-8') @@ -25,54 +27,6 @@ def clean_build_dir(build_dir): build_dir.mkdir(parents=True, exist_ok=True) -class BuildResult: - # Windows example with absolute paths: - # [...]/build-x64-windows-release/ - build: Path - # [...]/build-x64-windows-release/bin - bin: Path - # [...]/build-x64-windows-release/ScreenPlay-Installer.exe - installer: Path - # [...]/build-x64-windows-release/ScreenPlay-Installer.zip - installer_zip: Path - # [...]/build-x64-windows-release/ScreenPlay-0.X.0-RCX-x64-windows-release.zip - build_zip: Path - # [...]/build-x64-windows-release/ScreenPlay-0.X.0-RCX-x64-windows-release.txt :sha256, needed for scoop - build_hash: Path - # x64, arm64, universal - build_arch: str - -class BuildConfig: - root_path: str - cmake_osx_architectures: str - cmake_target_triplet: str - package: bool - osx_bundle: str - package_command: str - executable_file_ending: str - # qt_* use either aqt or from the maintenance tool - qt_path: str # C:\Qt - qt_bin_path: str # C:\Qt\6.3.2\msvc2019_64 - qt_version: str - qt_ifw_version: str - ifw_root_path: str - cmake_toolchain_file: str - aqt_install_qt_packages: str - aqt_install_tool_packages: str - executable_file_ending: str - build_folder: str - bin_dir: str - screenplay_version: str - # CMake variables need str: "ON" or "OFF" - build_steam: str - build_tests: str - build_deploy: str - build_type: str - build_architecture: str - create_installer: str - sign_osx: bool - - def execute( build_config: BuildConfig ) -> BuildResult: @@ -90,12 +44,12 @@ def execute( # 3rd party tools like the crashreporter create local # temporary files in the build directory. clean_build_dir(build_config.build_folder) - + # Runs cmake configure and cmake build step_time = time.time() build_result = build(build_config, build_result) build_duration = time.time() - step_time - #print(f"ā±ļø build_duration (for {build_config.build_architecture}): {build_duration}s") + print(f"ā±ļø build_duration: {build_duration}s") # Copies all needed libraries and assets into the bin folder step_time = time.time() @@ -103,6 +57,11 @@ def execute( package_duration = time.time() - step_time print(f"ā±ļø package_duration: {package_duration}s") + if platform.system() == "Darwin": + if (build_config.sign_osx): + print(f"Sign binary at: {build_config.bin_dir}") + macos_sign.sign(build_config=build_config) + # Creates a Qt InstallerFrameWork (IFW) installer if build_config.create_installer == "ON": step_time = time.time() @@ -110,8 +69,14 @@ def execute( build_installer_duration = time.time() - step_time print(f"ā±ļø build_installer_duration: {build_installer_duration}s") - # Create a zip file for scoop & chocolatey - if platform.system() == "Windows": + if platform.system() == "Darwin": + if (build_config.sign_osx): + print( + f"Sign ScreenPlay-installer.dmg at: {build_config.bin_dir}") + macos_sign.sign_dmg(build_config=build_config) + + # Create a zip file of the build + if platform.system() != "Darwin": step_time = time.time() build_result = zip(build_config, build_result) zip_duration = time.time() - step_time @@ -122,9 +87,11 @@ def execute( # Print BuildConfig & BuildResult member for easier debugging print("\nšŸ†— BuildResult:") - print(' '.join("\n- %s: \t\t%s" % item for item in vars(build_result).items())) + print(' '.join("\n- %s: \t\t%s" % + item for item in vars(build_result).items())) print("\nāš™ļø BuildConfig:") - print(' '.join("\n- %s: \t\t%s" % item for item in vars(build_config).items())) + print(' '.join("\n- %s: \t\t%s" % + item for item in vars(build_config).items())) return build_result @@ -134,10 +101,13 @@ def setup(build_config: BuildConfig) -> Tuple[BuildConfig, BuildResult]: build_config.qt_path = defines.QT_PATH if not build_config.qt_path.exists(): - print(f"Qt path does not exist at {build_config.qt_path}. Please make sure to run setup.py!") + print( + f"Qt path does not exist at {build_config.qt_path}. Please make sure to run setup.py!") exit(2) - build_config.qt_bin_path = Path(build_config.qt_path).joinpath(f"{build_config.qt_version}/{defines.QT_PLATFORM}").resolve() - build_config.ifw_root_path = Path(f"{build_config.qt_path}/Tools/QtInstallerFramework/{build_config.qt_ifw_version}").resolve() + build_config.qt_bin_path = Path(build_config.qt_path).joinpath( + f"{build_config.qt_version}/{defines.QT_PLATFORM}").resolve() + build_config.ifw_root_path = Path( + f"{build_config.qt_path}/Tools/QtInstallerFramework/{build_config.qt_ifw_version}").resolve() if platform.system() == "Windows": build_config.cmake_target_triplet = "x64-windows" @@ -157,10 +127,10 @@ def setup(build_config: BuildConfig) -> Tuple[BuildConfig, BuildResult]: build_config.cmake_target_triplet = "64-osx-universal" build_config.executable_file_ending = ".app" # NO f string we fill it later! - #build_config.package_command = "{prefix_path}/bin/macdeployqt ScreenPlay.app -qmldir=../../{app}/qml -executable=ScreenPlay.app/Contents/MacOS/{app} -appstore-compliant -timestamp -hardened-runtime" + # build_config.package_command = "{prefix_path}/bin/macdeployqt ScreenPlay.app -qmldir=../../{app}/qml -executable=ScreenPlay.app/Contents/MacOS/{app} -appstore-compliant -timestamp -hardened-runtime" build_config.aqt_install_qt_packages = f"mac desktop {build_config.qt_version} clang_64 -m all" build_config.aqt_install_tool_packages = "mac desktop tools_ifw" - + elif platform.system() == "Linux": build_config.cmake_target_triplet = "x64-linux" build_config.executable_file_ending = "" @@ -171,21 +141,27 @@ def setup(build_config: BuildConfig) -> Tuple[BuildConfig, BuildResult]: "Unsupported platform, ScreenPlay only supports Windows, macOS and Linux.") # Prepare - build_config.cmake_toolchain_file = Path(f"{build_config.root_path}/../vcpkg/scripts/buildsystems/vcpkg.cmake").resolve() + build_config.cmake_toolchain_file = Path( + f"{build_config.root_path}/../vcpkg/scripts/buildsystems/vcpkg.cmake").resolve() print(f"cmake_toolchain_file: {build_config.cmake_toolchain_file}") print(f"Starting build with type {build_config.build_type}.") - print(f"Qt Version: {build_config.qt_version}. Root path: {build_config.root_path}") + print( + f"Qt Version: {build_config.qt_version}. Root path: {build_config.root_path}") # Remove old build folder to before configuring to get rid of all cmake chaches - build_config.build_folder = build_config.root_path.joinpath(f"build-{build_config.cmake_target_triplet}-{build_config.build_type}") + build_config.build_folder = build_config.root_path.joinpath( + f"build-{build_config.cmake_target_triplet}-{build_config.build_type}") build_config.bin_dir = build_config.build_folder.joinpath("bin") if platform.system() == "Windows": - build_result.installer = Path(build_config.build_folder).joinpath("ScreenPlay-Installer.exe") + build_result.installer = Path(build_config.build_folder).joinpath( + "ScreenPlay-Installer.exe") elif platform.system() == "Darwin": - build_result.installer = Path(build_config.build_folder).joinpath("ScreenPlay.dmg") + build_result.installer = Path( + build_config.build_folder).joinpath("ScreenPlay.dmg") elif platform.system() == "Linux": - build_result.installer = Path(build_config.build_folder).joinpath("ScreenPlay-Installer.run") + build_result.installer = Path(build_config.build_folder).joinpath( + "ScreenPlay-Installer.run") return build_config, build_result @@ -201,7 +177,7 @@ def build(build_config: BuildConfig, build_result: BuildResult) -> BuildResult: -DSCREENPLAY_DEPLOY={build_config.build_deploy} \ -DSCREENPLAY_INSTALLER={build_config.create_installer} \ -DSCREENPLAY_IFW_ROOT:STRING={build_config.ifw_root_path} \ - -G "CodeBlocks - Ninja" \ + -G "Ninja" \ -B.' print(f"\nāš™ļø CMake configure:\n", cmake_configure_command.replace( @@ -220,20 +196,21 @@ def package(build_config: BuildConfig): if platform.system() == "Darwin": # Make sure to reset to tools path os.chdir(repo_root_path()) - cmd_raw = "{qt_bin_path}/macdeployqt {build_bin_dir}/ScreenPlay.app -qmldir={repo_root_path}/{app}/qml -executable={build_bin_dir}/ScreenPlay.app/Contents/MacOS/{app} -verbose=1 -appstore-compliant -timestamp -hardened-runtime " # -sign-for-notarization=\"Developer ID Application: Elias Steurer (V887LHYKRH)\" - build_bin_dir = Path(repo_root_path()).joinpath(f"{build_config.build_folder}/bin/") - cwd = Path(repo_root_path()).joinpath(f"{build_bin_dir}/ScreenPlay.app/Contents/MacOS/") + # -sign-for-notarization=\"Developer ID Application: Elias Steurer (V887LHYKRH)\" + cmd_raw = "{qt_bin_path}/macdeployqt {build_bin_dir}/ScreenPlay.app -qmldir={repo_root_path}/{app}/qml -executable={build_bin_dir}/ScreenPlay.app/Contents/MacOS/{app} -verbose=1 -appstore-compliant -timestamp -hardened-runtime " + build_bin_dir = Path(repo_root_path()).joinpath( + f"{build_config.build_folder}/bin/") + cwd = Path(repo_root_path()).joinpath( + f"{build_bin_dir}/ScreenPlay.app/Contents/MacOS/") qt_bin_path = Path(defines.QT_BIN_PATH).resolve() source_path = Path(repo_root_path()).resolve() - run(cmd=cmd_raw.format(qt_bin_path=qt_bin_path,repo_root_path=source_path, build_bin_dir=build_bin_dir, app="ScreenPlay"), cwd=cwd) - run(cmd=cmd_raw.format(qt_bin_path=qt_bin_path,repo_root_path=source_path, build_bin_dir=build_bin_dir, app="ScreenPlayWallpaper"), cwd=cwd) - run(cmd=cmd_raw.format(qt_bin_path=qt_bin_path,repo_root_path=source_path, build_bin_dir=build_bin_dir, app="ScreenPlayWidget"), cwd=cwd) - - if(build_config.sign_osx): - print(f"Sign binary at: {build_config.bin_dir}") - macos_sign.sign(build_config=build_config) - + run(cmd=cmd_raw.format(qt_bin_path=qt_bin_path, repo_root_path=source_path, + build_bin_dir=build_bin_dir, app="ScreenPlay"), cwd=cwd) + run(cmd=cmd_raw.format(qt_bin_path=qt_bin_path, repo_root_path=source_path, + build_bin_dir=build_bin_dir, app="ScreenPlayWallpaper"), cwd=cwd) + run(cmd=cmd_raw.format(qt_bin_path=qt_bin_path, repo_root_path=source_path, + build_bin_dir=build_bin_dir, app="ScreenPlayWidget"), cwd=cwd) if platform.system() == "Windows": print("Executing deploy commands...") @@ -291,8 +268,6 @@ def package(build_config: BuildConfig): shutil.copy(str(file), str(build_config.bin_dir)) print("Copied %s" % file) - - # Some dlls like openssl do no longer get copied automatically. # Lets just copy all of them into bin. if platform.system() == "Windows": @@ -326,6 +301,7 @@ def build_installer(build_config: BuildConfig, build_result: BuildResult): print("Running cpack at: ", os.getcwd()) run("cpack", cwd=build_config.build_folder) + def zip(build_config: BuildConfig, build_result: BuildResult) -> BuildResult: zipName = f"ScreenPlay-{build_config.screenplay_version}-{build_config.cmake_target_triplet}-{build_config.build_type}.zip" build_result.build_zip = Path(build_result.build).joinpath(zipName) @@ -346,9 +322,11 @@ def zip(build_config: BuildConfig, build_result: BuildResult) -> BuildResult: # Some weird company firewalls do not allow direct .exe downloads # lets just zip the installer lol if build_config.create_installer == "ON": - build_result.installer_zip = Path(build_result.build).joinpath(build_result.installer.stem + ".zip") + build_result.installer_zip = Path(build_result.build).joinpath( + build_result.installer.stem + ".zip") print(f"Create zip from installer: {build_result.installer_zip}") - zipfile.ZipFile(build_result.installer_zip, 'w').write(build_result.installer, build_result.installer.name) + zipfile.ZipFile(build_result.installer_zip, 'w').write( + build_result.installer, build_result.installer.name) return build_result @@ -357,35 +335,47 @@ if __name__ == "__main__": parser = argparse.ArgumentParser( description='Build and Package ScreenPlay') - - parser.add_argument('-qt-version', action="store", dest="qt_version_overwrite", + parser.add_argument('--qt-version', action="store", dest="qt_version_overwrite", help="Overwrites the default Qt version") - parser.add_argument('-qt-installer-version', action="store", dest="qt_installer_version_overwrite", + parser.add_argument('--qt-installer-version', action="store", dest="qt_installer_version_overwrite", help="Overwrites the default Qt installer framework version") - parser.add_argument('-type', action="store", dest="build_type", default="release", + parser.add_argument('--type', action="store", dest="build_type", default="release", help="Build type. This is either debug or release.") - parser.add_argument('-use-aqt', action="store_true", dest="use_aqt", + parser.add_argument('--use-aqt', action="store_true", dest="use_aqt", help="Absolute qt path. If not set the default path is used\Windows: C:\Qt\nLinux & macOS:~/Qt/.") - parser.add_argument('-steam', action="store_true", dest="build_steam", + parser.add_argument('--steam', action="store_true", dest="build_steam", help="Enable if you want to build the Steam workshop plugin.") - parser.add_argument('-tests', action="store_true", dest="build_tests", + parser.add_argument('--tests', action="store_true", dest="build_tests", help="Build tests.") - parser.add_argument('-installer', action="store_true", dest="create_installer", + parser.add_argument('--installer', action="store_true", dest="create_installer", help="Create a installer.") - parser.add_argument('-sign_osx', action="store_true", dest="sign_osx", default=False, + parser.add_argument('--sign_osx', action="store_true", dest="sign_osx", default=False, help="Signs the executable on macOS. This requires a valid Apple Developer ID set up.") - parser.add_argument('-deploy-version', action="store_true", dest="build_deploy", + parser.add_argument('--deploy-version', action="store_true", dest="build_deploy", help="Create a deploy version of ScreenPlay for sharing with the world. A not deploy version is for local development only!") - parser.add_argument('-architecture', action="store", dest="build_architecture", default="", + parser.add_argument('--architecture', action="store", dest="build_architecture", default="", help="Sets the build architecture. Used to build x86 and ARM osx versions. Currently only works with x86_64 and arm64") args = parser.parse_args() qt_version = defines.QT_VERSION - screenplay_version = defines.SCREENPLAY_VERSION qt_ifw_version = defines.QT_IFW_VERSION # Not yet used. qt_version_overwrite: str use_aqt = False + tag = get_latest_git_tag() + if tag: + print(f"Latest Git tag: {tag}") + semver = parse_semver(tag) + if semver: + print(f"Parsed SemVer: {semver}") + screenplay_version = semver_to_string(semver) + else: + print("Failed to parse SemVer.") + exit(-1) + else: + print("No git tags found.") + exit(-1) + if args.qt_version_overwrite: qt_version = args.qt_version_overwrite print("Using Qt version {qt_version}") diff --git a/Tools/build_and_publish.py b/Tools/build_and_publish.py deleted file mode 100644 index 3e49f7b5..00000000 --- a/Tools/build_and_publish.py +++ /dev/null @@ -1,107 +0,0 @@ -#!/usr/bin/python3 -# SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only -import steam_publish -import shutil -import sys -import macos_sign -import argparse -import os -import build -from pathlib import Path -import platform -import paramiko -import defines -from util import sftp_exists, run, repo_root_path -from sys import stdout - -stdout.reconfigure(encoding='utf-8') - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description='Build and Package ScreenPlay') - parser.add_argument('-skip_publish', '-skp', action="store_true", dest="skip_publish", default=False, help="skip publish") - parser.add_argument('-skip_build', '-skb', action="store_true", dest="skip_build", default=False, help="skip build. If we already have a build and only want to upload it") - parser.add_argument('-steam_password', '-sp', action="store", dest="steam_password", help="Steam password") - parser.add_argument('-hosting_username','-hu', action="store", dest="hosting_username", help="ssh username") - parser.add_argument('-hosting_password', '-hp', action="store", dest="hosting_password", help="ssh password") - args = parser.parse_args() - - # Script needs to run in the tools folder - tools_path = Path.cwd() - os.chdir(tools_path) - root_path = tools_path.parent - print(f"Set root directory to: {root_path}") - - build_result = build.BuildResult() - - build_config = build.BuildConfig() - build_config.screenplay_version = defines.SCREENPLAY_VERSION - build_config.qt_version = defines.QT_VERSION - build_config.qt_ifw_version = defines.QT_IFW_VERSION - build_config.build_steam = "ON" - build_config.build_tests = "OFF" - build_config.build_deploy = "ON" - build_config.create_installer = "ON" - build_config.build_type = "release" - - if platform.system() == "Darwin" and not args.skip_build: - # We do not yet support a standalone osx installer - build_config.create_installer = "OFF" - - # We need to manually package here at the end after - build_config.package = True - build_config.sign_osx = True - - # This will build both arm64 and x64 and sign the unversal binary - build_result = build.execute(build_config) - - - if platform.system() == "Windows" and not args.skip_build: - build_config.build_architecture = "x64" - - if not args.skip_publish: - # Steamless version first - build_config.build_steam = "OFF" - build_result = build.execute(build_config) - ssh = paramiko.SSHClient() - ssh.load_system_host_keys() - ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - ssh.connect('kelteseth.com', username=args.hosting_username, password=args.hosting_password) - sftp = ssh.open_sftp() - release_folder = "/kelteseth_com/public/releases/" + build_config.screenplay_version + "/" - if sftp_exists(sftp,release_folder): - remoteFiles = sftp.listdir(path=release_folder) - for file in remoteFiles: - print(f"Delte old: {release_folder+file}") - sftp.remove(release_folder+file) - else: - sftp.mkdir(release_folder) - print("Uploading files...") - - sftp.put(build_result.build_zip, release_folder + str(build_result.build_zip.name)) - sftp.put(build_result.installer, release_folder + str(build_result.installer.name)) - sftp.put(build_result.installer_zip,release_folder + str(build_result.installer_zip.name)) - sftp.put(build_result.build_hash, release_folder + str(build_result.build_hash.name)) - sftp.close() - ssh.close() - - # Now build the steam version - os.chdir(tools_path) - build_config.build_steam = "ON" - build_config.create_installer = "OFF" - build_result = build.execute(build_config) - - if args.skip_publish: - print("Skip publishing.") - sys.exit(0) - - if args.steam_password is None: - print("Steam password is required.") - sys.exit(1) - - # Make sure to reset to tools path - os.chdir(tools_path) - steam_publish.publish( - steam_username="tachiom", - steam_password=args.steam_password, - set_live_branch_name="internal" - ) diff --git a/Tools/build_and_publish_steam.py b/Tools/build_and_publish_steam.py new file mode 100644 index 00000000..4f45725c --- /dev/null +++ b/Tools/build_and_publish_steam.py @@ -0,0 +1,94 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only +import steam_publish +import sys +import argparse +import os +import build +from pathlib import Path +import platform +import defines +from build_result import BuildResult +from build_config import BuildConfig +from util import get_latest_git_tag, parse_semver, semver_to_string +from sys import stdout + +stdout.reconfigure(encoding='utf-8') + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description='Build and Package ScreenPlay') + parser.add_argument('--skip_steam_publish', '-skstp', action="store_true", + dest="skip_steam_publish", default=False, help="skip publish") + parser.add_argument('--skip_build', '-skb', action="store_true", dest="skip_build", + default=False, help="skip build. If we already have a build and only want to upload it") + parser.add_argument('--steam_password', '-sp', action="store", + dest="steam_password", help="Steam password") + parser.add_argument('--hosting_username', '-hu', action="store", + dest="hosting_username", help="ssh username") + parser.add_argument('--hosting_password', '-hp', action="store", + dest="hosting_password", help="ssh password") + args = parser.parse_args() + + if not args.skip_steam_publish and args.steam_password is None: + print("Steam password is required.") + sys.exit(1) + + if not steam_publish.check_steam_login("tachiom", args.steam_password): + print("Failed to login to Steam!") + exit(1) + + # Script needs to run in the tools folder + tools_path = Path.cwd() + os.chdir(tools_path) + root_path = tools_path.parent + print(f"Set root directory to: {root_path}") + + tag = get_latest_git_tag() + if tag: + print(f"Latest Git tag: {tag}") + semver = parse_semver(tag) + if semver: + print(f"Parsed SemVer: {semver}") + screenplay_version = semver_to_string(semver) + else: + print("Failed to parse SemVer.") + exit(-1) + else: + print("No git tags found.") + exit(-1) + + build_result = BuildResult() + + build_config = BuildConfig() + build_config.qt_version = defines.QT_VERSION + build_config.qt_ifw_version = defines.QT_IFW_VERSION + build_config.build_steam = "ON" + build_config.build_tests = "OFF" + build_config.build_deploy = "ON" + build_config.create_installer = "OFF" + build_config.build_type = "release" + build_config.screenplay_version = screenplay_version + + if platform.system() == "Darwin" and not args.skip_build: + # We need to manually package here at the end after + build_config.package = True + build_config.sign_osx = True + + # This will build both arm64 and x64 and sign the unversal binary + build_result = build.execute(build_config) + + if platform.system() == "Windows" and not args.skip_build: + build_result = build.execute(build_config) + + if args.skip_steam_publish: + print("Skip steam publishing.") + sys.exit(0) + + # Make sure to reset to tools path + os.chdir(tools_path) + steam_publish.publish( + steam_username="tachiom", + steam_password=args.steam_password, + set_live_branch_name="internal" + ) diff --git a/Tools/build_config.py b/Tools/build_config.py new file mode 100644 index 00000000..0241c29b --- /dev/null +++ b/Tools/build_config.py @@ -0,0 +1,29 @@ +class BuildConfig: + root_path: str + cmake_osx_architectures: str + cmake_target_triplet: str + package: bool + osx_bundle: str + package_command: str + executable_file_ending: str + # qt_* use either aqt or from the maintenance tool + qt_path: str # C:\Qt + qt_bin_path: str # C:\Qt\6.3.2\msvc2019_64 + qt_version: str + qt_ifw_version: str + ifw_root_path: str + cmake_toolchain_file: str + aqt_install_qt_packages: str + aqt_install_tool_packages: str + executable_file_ending: str + build_folder: str + bin_dir: str + screenplay_version: str + # CMake variables need str: "ON" or "OFF" + build_steam: str + build_tests: str + build_deploy: str + build_type: str + build_architecture: str + create_installer: str + sign_osx: bool diff --git a/Tools/build_result.py b/Tools/build_result.py new file mode 100644 index 00000000..d253123b --- /dev/null +++ b/Tools/build_result.py @@ -0,0 +1,20 @@ + +from pathlib import Path + + +class BuildResult: + # Windows example with absolute paths: + # [...]/build-x64-windows-release/ + build: Path + # [...]/build-x64-windows-release/bin + bin: Path + # [...]/build-x64-windows-release/ScreenPlay-Installer.exe + installer: Path + # [...]/build-x64-windows-release/ScreenPlay-Installer.zip + installer_zip: Path + # [...]/build-x64-windows-release/ScreenPlay-0.X.0-RCX-x64-windows-release.zip + build_zip: Path + # [...]/build-x64-windows-release/ScreenPlay-0.X.0-RCX-x64-windows-release.txt :sha256, needed for scoop + build_hash: Path + # x64, arm64, universal + build_arch: str diff --git a/Tools/check_format_cmake.py b/Tools/check_format_cmake.py new file mode 100644 index 00000000..c3d1849a --- /dev/null +++ b/Tools/check_format_cmake.py @@ -0,0 +1,56 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only +import os +import argparse +import util +from format_util import find_files +from format_util import execute_threaded +from sys import stdout + +stdout.reconfigure(encoding='utf-8') + + +def format_file_function(file): + executable = "cmake-format" + if os.name == 'nt': + executable += ".exe" + os.system(" %s -c ../.cmake-format.py -i %s" % (executable, file)) + print("Format: ", file) + + +def check_format_file_function(file): + executable = "cmake-format" + if os.name == 'nt': + executable += ".exe" + result = os.system(" %s -c ../.cmake-format.py --check %s" % + (executable, file)) + + # If the return code is non-zero, the file isn't formatted correctly + if result != 0: + print(f"{file} is not correctly formatted.") + return False + return True + + +def main(git_staged_only=False, check_only=False): + file_list = find_files( + ('CMakeLists.txt', '*.cmake'), util.repo_root_path(), git_staged_only) + + if check_only: + result = execute_threaded(file_list, check_format_file_function) + if not result: # Since result is a single boolean, you can directly check its value + print("Some files are not correctly formatted!") + exit(1) + else: + execute_threaded(file_list, format_file_function) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument('-s', '--stage-only', action="store_true", dest="stage_only", default=False, + help="Check/format only staged files") + parser.add_argument('-c', '--check', action="store_true", dest="check_only", default=False, + help="Only check if files are correctly formatted without actually formatting them") + + args = parser.parse_args() + main(args.stage_only, args.check_only) diff --git a/Tools/check_format_cpp.py b/Tools/check_format_cpp.py new file mode 100644 index 00000000..793135f3 --- /dev/null +++ b/Tools/check_format_cpp.py @@ -0,0 +1,61 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only +import os +import subprocess +import argparse +import util +from format_util import find_files +from format_util import execute_threaded +from sys import stdout + +stdout.reconfigure(encoding='utf-8') + + +def format_file_function(file): + executable = "clang-format" + if os.name == 'nt': + executable = "clang-format.exe" + process = subprocess.run(" %s -style=file -i %s" % + (executable, file), capture_output=True, shell=True) + print("Format: %s \t return: %s" % (file, process.returncode)) + + +def check_format_file_function(file): + executable = "clang-format" + if os.name == 'nt': + executable += ".exe" + result = subprocess.run(" %s -style=file --output-replacements-xml %s" % + (executable, file), capture_output=True, shell=True, text=True) + + # Check for opening replacement tag with attributes (a space after it indicates attributes) + if "` @@ -34,32 +34,41 @@ def sign(build_config: BuildConfig): # id: xxxxxx-xxxxxx-xxxx-xxxxx-xxxxx # status: Invalid print("Run xcnotary submit") - run("xcrun notarytool submit --keychain-profile 'ScreenPlay' ScreenPlay.app.zip --wait", cwd=build_config.bin_dir) + run("xcrun notarytool submit --keychain-profile 'ScreenPlay' ScreenPlay.app.zip --wait", + cwd=build_config.bin_dir) print("Run stapler staple") run("xcrun stapler staple ScreenPlay.app", cwd=build_config.bin_dir) print("Run spctl assess") run("spctl --assess --verbose 'ScreenPlay.app/'", cwd=build_config.bin_dir) - print("Remove *.app.zip files.") + print("Remove ScreenPlay.app.zip.") run("rm ScreenPlay.app.zip", cwd=build_config.bin_dir) - - # We also need to sign the installer in osx: - if build_config.create_installer == "ON": - run("codesign --deep -f -s \"Developer ID Application: Elias Steurer (V887LHYKRH)\" --timestamp --options \"runtime\" -f --deep \"ScreenPlay-Installer.dmg/ScreenPlay-Installer.app/Contents/MacOS/ScreenPlay-Installer\"", cwd=build_config.build_folder) - run("codesign --verify --verbose=4 \"ScreenPlay-Installer.dmg/ScreenPlay-Installer.app/Contents/MacOS/ScreenPlay-Installer\"", - cwd=build_config.build_folder) - run("xcnotary notarize ScreenPlay-Installer.dmg/ScreenPlay-Installer.app -d kelteseth@gmail.com -k ScreenPlay", - cwd=build_config.build_folder) - run("spctl --assess --verbose \"ScreenPlay-Installer.dmg/ScreenPlay-Installer.app/\"", - cwd=build_config.build_folder) - run("codesign --deep -f -s \"Developer ID Application: Elias Steurer (V887LHYKRH)\" --timestamp --options \"runtime\" -f --deep \"ScreenPlay-Installer.dmg/\"", cwd=build_config.build_folder) - run("codesign --verify --verbose=4 \"ScreenPlay-Installer.dmg/\"", - cwd=build_config.build_folder) - run("xcnotary notarize ScreenPlay-Installer.dmg -d kelteseth@gmail.com -k ScreenPlay", - cwd=build_config.build_folder) - run("spctl --assess --verbose \"ScreenPlay-Installer.dmg/\"", - cwd=build_config.build_folder) +def sign_dmg(build_config: BuildConfig): + # Sign the DMG + run("codesign -f -s \"Developer ID Application: Elias Steurer (V887LHYKRH)\" --timestamp --options \"runtime\" -f --deep \"ScreenPlay-Installer.dmg\"", cwd=build_config.build_folder) + # Verify the DMG's signature + run("codesign --verify --verbose=4 \"ScreenPlay-Installer.dmg\"", + cwd=build_config.build_folder) + + # Pack the DMG for notarization + run("ditto -c -k --keepParent ScreenPlay-Installer.dmg ScreenPlay-Installer.dmg.zip", + cwd=build_config.build_folder) + + # Notarize the DMG using notarytool + run("xcrun notarytool submit ScreenPlay-Installer.dmg.zip --keychain-profile 'ScreenPlay' --wait", + cwd=build_config.build_folder) + + # Staple the notarization ticket to the DMG + run("xcrun stapler staple ScreenPlay-Installer.dmg", + cwd=build_config.build_folder) + + # Check the notarization status for the DMG + run("spctl --assess --verbose \"ScreenPlay-Installer.dmg\"", + cwd=build_config.build_folder) + + # Clean up the zip file + run("rm ScreenPlay-Installer.dmg.zip", cwd=build_config.build_folder) diff --git a/Tools/qml_format.py b/Tools/qml_format.py deleted file mode 100644 index ab0e94e5..00000000 --- a/Tools/qml_format.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/python3 -# SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only -import os -import subprocess -import argparse -import sys -import defines -from format_util import find_files -from format_util import check_git_exit -from format_util import execute_threaded -from sys import stdout - -stdout.reconfigure(encoding='utf-8') - - -def format_file_function(file): - executable = "qmlformat" - if os.name == 'nt': - executable = "qmlformat.exe" - qt_bin_path = defines.QT_BIN_PATH - executable = qt_bin_path.joinpath(executable) - - process = subprocess.run( - "%s -i %s" % (executable, file), capture_output=True, shell=True) - print("Format: %s \t return: %s" % (file, process.returncode)) - - -def main(git_staged_only=False): - file_list = find_files(('.qml'), os.path.abspath(os.path.join(os.getcwd(), "../")), git_staged_only) - execute_threaded(file_list, format_file_function) - if not git_staged_only: - check_git_exit("QML Format") - - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument('-s', action="store_true", dest="stage_only", - default=False) - args = parser.parse_args() - main(args.stage_only) diff --git a/Tools/requirements.txt b/Tools/requirements.txt index 99e4a8f3..9a567f28 100644 --- a/Tools/requirements.txt +++ b/Tools/requirements.txt @@ -1,3 +1,2 @@ cmake-format -paramiko aqtinstall \ No newline at end of file diff --git a/Tools/steam_publish.py b/Tools/steam_publish.py index 2385cc92..cf9d7ab6 100644 --- a/Tools/steam_publish.py +++ b/Tools/steam_publish.py @@ -5,6 +5,7 @@ import sys import subprocess import shutil import argparse +from pathlib import Path from sys import platform from execute_util import execute from datetime import datetime @@ -16,6 +17,67 @@ from sys import stdout stdout.reconfigure(encoding='utf-8') + +class PublishConfig: + vdf_config_name: str + depot_config_name: str + steamcmd_path: Path + + +def init_publish_config(): + config = PublishConfig() + + root_path = cd_repo_root_path() + tools_path = os.path.join(root_path, "Tools") + contentBuiler_path = os.path.join(tools_path, "Steam/ContentBuilder/") + + if platform.system() == "Windows": + config.vdf_config_name = "app_build_windows.vdf" + config.depot_config_name = "depot_build_windows.vdf" + config.steamcmd_path = os.path.join( + contentBuiler_path, "builder/steamcmd.exe") + elif platform.system() == "Darwin": + config.vdf_config_name = "app_build_mac.vdf" + config.depot_config_name = "depot_build_mac.vdf" + config.steamcmd_path = os.path.join( + contentBuiler_path, "builder_osx/steamcmd") + execute(f"chmod +x {config.steamcmd_path}") + elif platform.system() == "Linux": + config.vdf_config_name = "app_build_linux.vdf" + config.depot_config_name = "depot_build_linux.vdf" + config.steamcmd_path = os.path.join( + contentBuiler_path, "builder_linux/steamcmd.sh") + execute(f"chmod +x {config.steamcmd_path}") + + return config + + +def check_steam_login(username: str, password: str): + config = init_publish_config() + cmd = [config.steamcmd_path, "+login", username, password, "+quit"] + + try: + with subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) as process: + try: + stdout, stderr = process.communicate( + timeout=60) # 1 minute timeout + for line in stdout.splitlines(): + print(line) # Print the line for debugging purposes + + if "Logging in user" in line: + return True + elif "Steam Guard code" in line: + process.terminate() + return False + except subprocess.TimeoutExpired: + process.kill() + print("Steam login check timed out after 1 minute.") + return False + except Exception as e: + print(f"Error during Steam login check: {e}") + return False + + # Executes steamcmd with username and password. Changes the content of the config # for better readability in the steam builds tab # https://partner.steamgames.com/apps/builds/672870 @@ -27,6 +89,7 @@ def get_git_revision_short_hash(): def get_git_commit_text(): return subprocess.check_output(['git', 'log', '-1', '--pretty=%B']) + def publish( steam_username, steam_password, @@ -36,30 +99,13 @@ def publish( # Make sure the script is always started from the same folder root_path = cd_repo_root_path() tools_path = os.path.join(root_path, "Tools") - contentBuiler_path = os.path.join(tools_path, "Steam/ContentBuilder/") - vdf_config_name = "" - depot_config_name = "" - steamcmd_path = "" - if platform.system() == "Windows": - vdf_config_name = "app_build_windows.vdf" - depot_config_name = "depot_build_windows.vdf" - steamcmd_path = os.path.join(contentBuiler_path, "builder/steamcmd.exe") - steamcmd_path = steamcmd_path.replace("/","\\") - elif platform.system() == "Darwin": - vdf_config_name = "app_build_mac.vdf" - depot_config_name = "depot_build_mac.vdf" - steamcmd_path = os.path.join(contentBuiler_path, "builder_osx/steamcmd") - execute(f"chmod +x {steamcmd_path}") - elif platform.system() == "Linux": - vdf_config_name = "app_build_linux.vdf" - depot_config_name = "depot_build_linux.vdf" - steamcmd_path = os.path.join(contentBuiler_path, "builder_linux/steamcmd.sh") - execute(f"chmod +x {steamcmd_path}") + config = init_publish_config() - print(f"Set steamCmd path: {steamcmd_path}") + print(f"Set steamCmd path: {config.steamcmd_path}") - abs_vdf_path = os.path.join(tools_path,"Steam/steamcmd/" + vdf_config_name) + abs_vdf_path = os.path.join( + tools_path, "Steam/steamcmd/" + config.vdf_config_name) if not os.path.isfile(abs_vdf_path): print("Incorrect vdf name") @@ -71,15 +117,19 @@ def publish( git_hash = get_git_revision_short_hash().decode("utf-8").replace("\n", "") git_commit_text = get_git_commit_text().decode("utf-8").replace("\n", "") # Remove ' and " that can occour it is a merge commit - git_commit_text = git_commit_text.replace('\"','') - git_commit_text = git_commit_text.replace('\'','') + git_commit_text = git_commit_text.replace('\"', '') + git_commit_text = git_commit_text.replace('\'', '') current_date_time = datetime.now().strftime("%d/%m/%Y, %H:%M:%S") - build_description = "- git hash: " + git_hash + ", commit: " + git_commit_text + " - upload datetime: " + current_date_time - config_content = config_content.replace("{{BUILD_DESCRIPTION}}", build_description) - config_content = config_content.replace("{{SET_LIVE_ON_BRANCH}}", set_live_branch_name) + build_description = "- git hash: " + git_hash + ", commit: " + \ + git_commit_text + " - upload datetime: " + current_date_time + config_content = config_content.replace( + "{{BUILD_DESCRIPTION}}", build_description) + config_content = config_content.replace( + "{{SET_LIVE_ON_BRANCH}}", set_live_branch_name) tmp_steam_config_foldername = "tmp_steam_config/" - tmp_steam_config_dir = os.path.abspath(os.path.join(tools_path,tmp_steam_config_foldername)) + tmp_steam_config_dir = os.path.abspath( + os.path.join(tools_path, tmp_steam_config_foldername)) if os.path.isdir(tmp_steam_config_dir): print(f"Deleting tmp config {tmp_steam_config_dir}") @@ -87,24 +137,30 @@ def publish( os.mkdir(tmp_steam_config_dir) - f = open(os.path.abspath(tmp_steam_config_dir + "/" + vdf_config_name), "w") + f = open(os.path.abspath(tmp_steam_config_dir + + "/" + config.vdf_config_name), "w") f.write(config_content) f.close() print(f"Using config:\n {config_content}\n") # We also must copy the depot file - abs_depot_path = os.path.join(tools_path, "Steam/steamcmd/" + depot_config_name) - copyfile(abs_depot_path, tmp_steam_config_dir + "/" + depot_config_name) + abs_depot_path = os.path.join( + tools_path, "Steam/steamcmd/" + config.depot_config_name) + copyfile(abs_depot_path, tmp_steam_config_dir + + "/" + config.depot_config_name) - tmp_steam_config_path = "\"" + os.path.abspath(os.path.join(tmp_steam_config_dir,vdf_config_name) ) + "\"" + tmp_steam_config_path = "\"" + \ + os.path.abspath(os.path.join( + tmp_steam_config_dir, config.vdf_config_name)) + "\"" print("Execute steamcmd on: " + tmp_steam_config_path) - execute(f"{steamcmd_path} +login {steam_username} {steam_password} +run_app_build {tmp_steam_config_path} +quit") + execute(f"{config.steamcmd_path} +login {steam_username} {steam_password} +run_app_build {tmp_steam_config_path} +quit") print("Deleting tmp config") shutil.rmtree(tmp_steam_config_dir) + if __name__ == "__main__": parser = argparse.ArgumentParser(description='Publish ScreenPlay to Steam') parser.add_argument('-steam_username', action="store", dest="steam_username", required=True, @@ -129,4 +185,4 @@ if __name__ == "__main__": steam_username=args.steam_username, steam_password=args.steam_password, set_live_branch_name=set_live_branch_name - ) \ No newline at end of file + ) diff --git a/Tools/util.py b/Tools/util.py index 1e1415c3..5a24cca1 100644 --- a/Tools/util.py +++ b/Tools/util.py @@ -6,11 +6,13 @@ from pathlib import Path from os import chdir from concurrent.futures import ThreadPoolExecutor import os +import re import subprocess from sys import stdout stdout.reconfigure(encoding='utf-8') + def sftp_exists(sftp, path) -> bool: try: sftp.stat(path) @@ -24,6 +26,7 @@ def run(cmd, cwd=Path.cwd()): if result.returncode != 0: raise RuntimeError(f"Failed to execute {cmd}") + def run_and_capture_output(cmd, cwd=Path.cwd()) -> str: result = subprocess.run(cmd, shell=True, cwd=cwd, stdout=subprocess.PIPE) if result.returncode != 0: @@ -31,14 +34,16 @@ def run_and_capture_output(cmd, cwd=Path.cwd()) -> str: if result.stdout is not None: return str(result.stdout.decode('utf-8')) return "" - + + def repo_root_path() -> str: # Root dir of the repository path = os.path.join(os.path.realpath(__file__), "../../") return os.path.realpath(path) + def cd_repo_root_path() -> str: - # Make sure the script is always started from the same + # Make sure the script is always started from the same # ScreenPlay root folder root_path = Path.cwd() if root_path.name == "Tools": @@ -47,6 +52,7 @@ def cd_repo_root_path() -> str: chdir(root_path) return root_path + def sha256(fname) -> str: hash_sha256 = hashlib.sha256() with open(fname, "rb") as f: @@ -55,7 +61,6 @@ def sha256(fname) -> str: return hash_sha256.hexdigest() - def zipdir(path, ziph): # ziph is zipfile handle for root, dirs, files in os.walk(path): @@ -102,3 +107,40 @@ def get_vs_env_dict(): raise ValueError(stderr.decode("mbcs")) output = stdout.decode("mbcs").split("\r\n") return dict((e[0].upper(), e[1]) for e in [p.rstrip().split("=", 1) for p in output] if len(e) == 2) + + +def get_latest_git_tag(): + try: + tag = subprocess.check_output( + ["git", "describe", "--tags"]).decode("utf-8").strip() + return tag + except subprocess.CalledProcessError: + print("Error fetching the Git tag.") + return None + + +def parse_semver(tag): + # Regular expression to match semver + # Like v0.15.1-RC1-305-g18b8c402 + # Do NOT add a - between RC and the version number (1 in this example) + pattern = r'(?i)^v?(\d+)\.(\d+)\.(\d+)(?:-([a-zA-Z0-9]+))?(?:-(\d+)-g([a-f0-9]+))?$' + match = re.match(pattern, tag) + if match: + major, minor, patch, pre_release, commits_since, commit_hash = match.groups() + return { + 'major': major, + 'minor': minor, + 'patch': patch, + 'pre_release': pre_release, + 'commits_since': commits_since, + 'commit_hash': commit_hash + } + else: + return None + + +def semver_to_string(semver_dict): + version_str = f"v{semver_dict['major']}.{semver_dict['minor']}.{semver_dict['patch']}" + if semver_dict['pre_release']: + version_str += f"-{semver_dict['pre_release']}" + return version_str