From f982002d808927c0f42dd7f384979c2781561003 Mon Sep 17 00:00:00 2001 From: Elias Steurer Date: Thu, 2 Nov 2023 12:50:29 +0100 Subject: [PATCH] Add ci support for godot Add automatic godot and exp --- .gitignore | 2 +- .vscode/launch.json | 26 ++-- CMake/CMakeVariables.h.in | 1 + CMake/GenerateCMakeVariableHeader.cmake | 5 +- CMakeLists.txt | 16 +- ScreenPlay/src/settings.cpp | 3 +- .../public/ScreenPlayUtil/logginghandler.h | 2 +- ScreenPlayUtil/qml/Dialogs/CriticalError.qml | 6 +- ScreenPlayUtil/src/logginghandler.cpp | 25 +++- .../Godot/ScreenPlayGodot/project.godot | 2 +- Tools/CMakeLists.txt | 2 +- Tools/build.py | 7 +- Tools/build_config.py | 1 + Tools/build_godot.py | 13 +- Tools/defines.py | 14 +- Tools/download_ffmpeg.py | 42 +++++- Tools/setup.py | 12 +- Tools/setup_godot.py | 141 ++++++++++++------ Tools/util.py | 34 +++++ 19 files changed, 258 insertions(+), 96 deletions(-) diff --git a/.gitignore b/.gitignore index f9de3484..228c4fbe 100644 --- a/.gitignore +++ b/.gitignore @@ -261,5 +261,5 @@ cython_debug/ /ThirdParty/qml-archive/** /ThirdParty/qml-plausible/ /ThirdParty/ffmpeg/** -/Tools/Apps/Godot/* /ThirdParty/qt-layer-shell/** +/ThirdParty/Godot/Godot_*.* diff --git a/.vscode/launch.json b/.vscode/launch.json index 57eefec2..0eaaad94 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,7 +5,7 @@ "version": "0.2.0", "configurations": [ { - "name": "Windows Launch", + "name": "🪟 Windows Launch", "type": "cppvsdbg", "request": "launch", "program": "${command:cmake.launchTargetPath}", @@ -23,26 +23,20 @@ "visualizerFile": "${workspaceFolder}/.vscode/qt.natvis.xml" }, { - "name": "Godot Editor", - "type": "cppvsdbg", - "request": "launch", - "program": "${workspaceFolder}\\Tools\\Apps\\Godot\\Godot_v4.1.1-stable_win64.exe", - "args": [ - "--path", - "${workspaceFolder}\\ScreenPlayWallpaper\\Godot\\ScreenPlayGodot", - "--editor" - ], - "stopAtEntry": false, - "preLaunchTask": "CMake: build", - "externalConsole": false - }, - { - "name": "macOS/linux Launch", + "name": "🍏macOS & 🐧linux Launch", "type": "lldb", "request": "launch", "program": "${command:cmake.launchTargetPath}", "args": [], "cwd": "${command:cmake.buildDirectory}/bin", + }, + { + "name": "🐍 Python: Current File", + "type": "python", + "request": "launch", + "program": "${file}", + "console": "integratedTerminal", + "justMyCode": true } ] } \ No newline at end of file diff --git a/CMake/CMakeVariables.h.in b/CMake/CMakeVariables.h.in index d616a317..e54ca0f3 100644 --- a/CMake/CMakeVariables.h.in +++ b/CMake/CMakeVariables.h.in @@ -2,3 +2,4 @@ #define SCREENPLAY_SOURCE_DIR "@SOURCE_DIR@" #define SCREENPLAY_GODOT_VERSION "@GODOT_VERSION@" +#define SCREENPLAY_GODOT_RELEASE_TYPE "@SCREENPLAY_GODOT_RELEASE_TYPE@" diff --git a/CMake/GenerateCMakeVariableHeader.cmake b/CMake/GenerateCMakeVariableHeader.cmake index 0cd7c0a9..41e6e489 100644 --- a/CMake/GenerateCMakeVariableHeader.cmake +++ b/CMake/GenerateCMakeVariableHeader.cmake @@ -1,4 +1,4 @@ -#! generate_cmake_variable_header : Generates a header CmakeVariables.h that contains defines for the variables specified in CmakeVariables.h.in! +# ! generate_cmake_variable_header : Generates a header CmakeVariables.h that contains defines for the variables specified in CmakeVariables.h.in! # # The generated CmakeVariables.h header can then be used to access e.g. the PROJECT_NAME define in C++ code. # @@ -6,12 +6,15 @@ # generate_cmake_variable_header(${PROJECT_NAME}) # function(generate_cmake_variable_header TARGET) + # NOTE: Also add to CMakeVariables.h.in ! set(SOURCE_DIR ${CMAKE_SOURCE_DIR}) set(SCREENPLAY_GODOT_VERSION ${GODOT_VERSION}) + set(SCREENPLAY_GODOT_RELEASE_TYPE ${GODOT_RELEASE_TYPE}) # Specify the configuration file from which the header file will be generated configure_file(${CMAKE_SOURCE_DIR}/CMake/CMakeVariables.h.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}/CMakeVariables.h @ONLY) message(STATUS "GENERATE: ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}/CMakeVariables.h and add ${TARGET} to ${CMAKE_CURRENT_BINARY_DIR}") + # Add the directory containing the generated header target_include_directories(${TARGET} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) endfunction() diff --git a/CMakeLists.txt b/CMakeLists.txt index 3252405c..e41656ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,14 +22,15 @@ elseif(APPLE) endif() # Godot Editor -set(GODOT_VERSION "v4.1.1") +set(GODOT_VERSION "v4.2") +set(GODOT_RELEASE_TYPE "beta4") if(WIN32) - set(GODOT_EDITOR_NAME "Godot_${GODOT_VERSION}-stable_win64.exe") + set(GODOT_EDITOR_NAME "Godot_${GODOT_VERSION}-${GODOT_RELEASE_TYPE}_win64.exe") elseif(APPLE) set(GODOT_EDITOR_NAME "Godot.app") elseif(UNIX) - set(GODOT_EDITOR_NAME "Godot_${GODOT_VERSION}-stable_linux.x86_64") + set(GODOT_EDITOR_NAME "Godot_${GODOT_VERSION}-${GODOT_RELEASE_TYPE}_linux.x86_64") else() message(FATAL_ERROR "Unsupported OS") endif() @@ -73,10 +74,10 @@ set(VCPKG_BIN_PATH "${VCPKG_INSTALLED_PATH}/bin") option(SCREENPLAY_STEAM "For FOSS distribution so we do not bundle proprietary code." ON) option(SCREENPLAY_DEPLOY "Marks this version as an official deploy version. This version uses different import paths and other settings." - OFF) + OFF) option(SCREENPLAY_TESTS "Enables UI tests." ON) option(SCREENPLAY_INSTALLER "Indicates whether an installer via the Qt Installer Framework is created." OFF) -option(SCREENPLAY_GODOT_SUPPORT "Compiles ScreenPlayGodotWallpaper." ON) +option(SCREENPLAY_GODOT_SUPPORT "Compiles ScreenPlayGodotWallpaper." OFF) # Gitlab CI has many ENV variables. We use this one to check if the current build happens inside the CI if(DEFINED ENV{CI_COMMIT_MESSAGE}) @@ -134,14 +135,15 @@ add_compile_definitions(GIT_COMMIT_HASH="${GIT_COMMIT_HASH}") add_subdirectory(ThirdParty) set(ECM_DIR "${THIRD_PARTY_PATH}/ecm") add_subdirectory(CMake) + if(UNIX AND NOT APPLE) # Needs to be append, because we include ecm as third party on linux list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake") list(APPEND CMAKE_MODULE_PATH "${ECM_DIR}") list(APPEND CMAKE_MODULE_PATH "${ECM_DIR}/cmake") else() - endif() + add_subdirectory(Tools) add_subdirectory(ScreenPlay) @@ -187,6 +189,8 @@ 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] GODOT_VERSION = ${GODOT_VERSION}") +message(STATUS "[PROJECT] GODOT_EDITOR_NAME = ${GODOT_EDITOR_NAME}") message(STATUS "[OPTION] SCREENPLAY_DEPLOY = ${SCREENPLAY_DEPLOY}") message(STATUS "[OPTION] SCREENPLAY_INSTALLER = ${SCREENPLAY_INSTALLER}") message(STATUS "[OPTION] SCREENPLAY_STEAM = ${SCREENPLAY_STEAM}") diff --git a/ScreenPlay/src/settings.cpp b/ScreenPlay/src/settings.cpp index 71fb536f..8555ebbf 100644 --- a/ScreenPlay/src/settings.cpp +++ b/ScreenPlay/src/settings.cpp @@ -157,11 +157,12 @@ void Settings::setupWidgetAndWindowPaths() const QString osType = QSysInfo::productType(); QString godotVersion = QString(SCREENPLAY_GODOT_VERSION); + QString godotReleaseType = QString(SCREENPLAY_GODOT_RELEASE_TYPE); if (osType == "windows") { m_globalVariables->setWidgetExecutablePath(QUrl(workingDir.path() + "/ScreenPlayWidget" + ScreenPlayUtil::executableBinEnding())); m_globalVariables->setWallpaperExecutablePath(QUrl(workingDir.path() + "/ScreenPlayWallpaper" + ScreenPlayUtil::executableBinEnding())); m_globalVariables->setGodotWallpaperExecutablePath(QUrl(workingDir.path() + "/ScreenPlayWallpaperGodot" + ScreenPlayUtil::executableBinEnding())); - const auto godotEditorName = "Godot_" + godotVersion + "-stable_win64.exe"; + const auto godotEditorName = "Godot_" + godotVersion + "-" + godotReleaseType + "_win64.exe"; m_globalVariables->setGodotEditorExecutablePath(QUrl(workingDir.path() + "/" + godotEditorName)); } else if (osType == "osx") { // ScreenPlayTest is not bundled in an .app so the working directory diff --git a/ScreenPlayUtil/inc/public/ScreenPlayUtil/logginghandler.h b/ScreenPlayUtil/inc/public/ScreenPlayUtil/logginghandler.h index a5b5a9e6..403a4d12 100644 --- a/ScreenPlayUtil/inc/public/ScreenPlayUtil/logginghandler.h +++ b/ScreenPlayUtil/inc/public/ScreenPlayUtil/logginghandler.h @@ -22,7 +22,7 @@ private: static QString toString(QtMsgType type); static QString extractFileName(const QMessageLogContext& context); static QString extractFunction(const QMessageLogContext& context); - static void writeToConsole(const QString& line, QtMsgType type); + static void writeToConsole(QtMsgType type, const QMessageLogContext& context, const QString& message); static void writeToFile(const QString& line); static void checkLogRotation(); static void loggingMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message); diff --git a/ScreenPlayUtil/qml/Dialogs/CriticalError.qml b/ScreenPlayUtil/qml/Dialogs/CriticalError.qml index 71680f9e..0c068f7a 100644 --- a/ScreenPlayUtil/qml/Dialogs/CriticalError.qml +++ b/ScreenPlayUtil/qml/Dialogs/CriticalError.qml @@ -15,7 +15,7 @@ Util.Dialog { property string message standardButtons: Dialog.Ok | Dialog.Help onHelpRequested: { - Qt.openUrlExternally("https://forum.screen-play.app/category/7/troubleshooting"); + Qt.openUrlExternally("https://forum.screen-play.app/"); } Connections { @@ -29,8 +29,8 @@ Util.Dialog { } contentItem: Item { - width: 600 - height: 400 + implicitWidth: 600 + implicitHeight: 400 ColumnLayout { anchors.margins: 20 diff --git a/ScreenPlayUtil/src/logginghandler.cpp b/ScreenPlayUtil/src/logginghandler.cpp index bac574cf..0b225b5a 100644 --- a/ScreenPlayUtil/src/logginghandler.cpp +++ b/ScreenPlayUtil/src/logginghandler.cpp @@ -36,6 +36,7 @@ LoggingHandler::LoggingHandler(const QString& logFileName) #endif + qSetMessagePattern("[%{time dd.MM.yyyy h:mm:ss.zzz} %{if-debug}Debug%{endif}%{if-info}Info%{endif}%{if-warning}Warning%{endif}%{if-critical}Critical%{endif}%{if-fatal}Fatal%{endif}] %{file}:%{line} - %{message}"); qInstallMessageHandler(LoggingHandler::loggingMessageHandler); const auto lock = std::lock_guard(logFileMutex()); m_logFileName = logFileName; @@ -193,29 +194,47 @@ QString LoggingHandler::extractFunction(const QMessageLogContext& context) * \brief LoggingHandler::writeToConsole * std::flush is used to fix QtCreator not printing output. */ -void LoggingHandler::writeToConsole(const QString& line, QtMsgType type) +void LoggingHandler::writeToConsole(QtMsgType type, const QMessageLogContext& context, const QString& message) { constexpr auto darkMode = true; auto color = fmt::color::black; + QString typeIndicator; switch (type) { case QtDebugMsg: color = fmt::color::green; + typeIndicator = "Debug"; break; case QtWarningMsg: color = fmt::color::orange; + typeIndicator = "Warning"; break; case QtCriticalMsg: color = fmt::color::magenta; + typeIndicator = "Critical"; break; case QtFatalMsg: color = fmt::color::red; + typeIndicator = "Fatal"; break; default: color = darkMode ? fmt::color::gray : fmt::color::black; + typeIndicator = "Info"; // Assuming default is info break; } - fmt::print("{}", fmt::styled(line.toStdString(), fg(color))); + + const auto now = QDateTime::currentDateTime().toString("dd.MM.yyyy h:mm:ss.zzz"); + const auto filename = extractFileName(context); + const auto function = extractFunction(context); + const auto line = context.line; + + fmt::print( + "[{}] {} {}:{} - {}\n", + fmt::styled(now.toStdString(), fmt::emphasis::bold), + fmt::styled(typeIndicator.toStdString(), fg(color)), + function.toStdString(), // Replace with context.file when QTCREATORBUG-24353 is fixed + line, + message.toStdString()); } void LoggingHandler::writeToFile(const QString& line) @@ -244,7 +263,7 @@ void LoggingHandler::checkLogRotation() void LoggingHandler::loggingMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { const QString line = LoggingHandler::logLine(type, context, message); - LoggingHandler::writeToConsole(line, type); + LoggingHandler::writeToConsole(type, context, message); LoggingHandler::writeToFile(line); } } diff --git a/ScreenPlayWallpaper/Godot/ScreenPlayGodot/project.godot b/ScreenPlayWallpaper/Godot/ScreenPlayGodot/project.godot index e719c85d..cb14a4c2 100644 --- a/ScreenPlayWallpaper/Godot/ScreenPlayGodot/project.godot +++ b/ScreenPlayWallpaper/Godot/ScreenPlayGodot/project.godot @@ -12,7 +12,7 @@ config_version=5 config/name="ScreenPlay" run/main_scene="res://main.tscn" -config/features=PackedStringArray("4.1", "Mobile") +config/features=PackedStringArray("4.2", "Mobile") run/flush_stdout_on_print=true boot_splash/bg_color=Color(0.141176, 0.141176, 0.141176, 0) boot_splash/show_image=false diff --git a/Tools/CMakeLists.txt b/Tools/CMakeLists.txt index 90f7c38d..56e20955 100644 --- a/Tools/CMakeLists.txt +++ b/Tools/CMakeLists.txt @@ -10,7 +10,7 @@ add_custom_target( SOURCES ${FILES} ${PYTHON} COMMENT "Dummy target to list these files in the IDE") -set(GODOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/Apps/Godot") +set(GODOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../ThirdParty/Godot") if(WIN32) # Todo: Add Linux and Mac support diff --git a/Tools/build.py b/Tools/build.py index 7f312a90..026f1e0c 100755 --- a/Tools/build.py +++ b/Tools/build.py @@ -13,6 +13,7 @@ from build_config import BuildConfig from typing import Tuple from pathlib import Path import macos_sign +import build_godot 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 @@ -51,6 +52,10 @@ def execute( build_duration = time.time() - step_time print(f"⏱️ build_duration: {build_duration}s") + # Build Godot Wallpaper + if platform.system() == "Windows": + build_godot.build_godot(str(build_config.bin_dir), build_config.build_type) + # Copies all needed libraries and assets into the bin folder step_time = time.time() package(build_config) @@ -384,7 +389,7 @@ if __name__ == "__main__": qt_ifw_version = args.qt_installer_version_overwrite print("Using Qt installer framework version {qt_ifw_version}") - build_type = args.build_type + build_type = args.build_type.lower() build_steam = "OFF" if args.build_steam: diff --git a/Tools/build_config.py b/Tools/build_config.py index 7bb3f8bc..824fb649 100644 --- a/Tools/build_config.py +++ b/Tools/build_config.py @@ -27,5 +27,6 @@ class BuildConfig: build_deploy: str build_type: str build_architecture: str + build_godot: str create_installer: str sign_osx: bool diff --git a/Tools/build_godot.py b/Tools/build_godot.py index b11cb743..5340703e 100644 --- a/Tools/build_godot.py +++ b/Tools/build_godot.py @@ -33,16 +33,21 @@ def main(): abs_build_path = args.build_path if not os.path.isabs(args.build_path): abs_build_path = os.path.abspath(os.path.join(os.getcwd(), args.build_path)) + + if 'Debug' in abs_build_path: + build_type = "debug" + else: + build_type = "release" - build_godot(abs_build_path) + build_godot(abs_build_path, build_type) -def build_godot(abs_build_path: str): +def build_godot(abs_build_path: str, build_type: str): project_path = Path(util.repo_root_path()).joinpath("ScreenPlayWallpaper/Godot/ScreenPlayGodot").resolve() - apps_path = os.path.join(util.repo_root_path(),"Tools/Apps/Godot") + apps_path = os.path.join(defines.THIRDPATH_PATH,"Godot") godot_executable = os.path.join(apps_path, defines.GODOT_EDITOR_EXECUTABLE) screenPlayWallpaperGodot_executable = Path(abs_build_path).joinpath(defines.SCREENPLAYWALLPAPER_GODOT_EXECUTABLE).resolve() - if 'Debug' in abs_build_path: + if 'debug' in build_type: export_type = " --export-debug" else: export_type = " --export-release" diff --git a/Tools/defines.py b/Tools/defines.py index 8035c016..dd47f09c 100644 --- a/Tools/defines.py +++ b/Tools/defines.py @@ -18,8 +18,9 @@ elif sys.platform == "linux": OS = "linux" QT_PLATFORM = "gcc_64" -QT_PATH = path = Path(os.path.join( - os.path.realpath(__file__), "../../../aqt")).resolve() +REPO_PATH = Path(__file__, "../../").resolve() +THIRDPATH_PATH = Path(REPO_PATH, "ThirdParty").resolve() +QT_PATH = path = Path(REPO_PATH, "../aqt").resolve() QT_VERSION = "6.6.0" QT_BIN_PATH = QT_PATH.joinpath(f"{QT_VERSION}/{QT_PLATFORM}/bin") QT_TOOLS_PATH = QT_PATH.joinpath("Tools/") @@ -34,10 +35,10 @@ VCPKG_BASE_PACKAGES = [ "catch2" ] PYTHON_EXECUTABLE = "python" if sys.platform == "win32" else "python3" -FFMPEG_VERSION = "5.0.1" - -GODOT_VERSION = "4.1.1" -GODOT_RELEASE_TYPE = "stable" +FFMPEG_VERSION = "6.0" +GODOT_VERSION = "4.2" +GODOT_RELEASE_TYPE = "beta4" +GODOT_DOWNLOAD_SERVER = "https://downloads.tuxfamily.org/godotengine" if sys.platform == "win32": SCREENPLAYWALLPAPER_GODOT_EXECUTABLE = "ScreenPlayWallpaperGodot.exe" GODOT_EDITOR_EXECUTABLE = f"Godot_v{GODOT_VERSION}-{GODOT_RELEASE_TYPE}_win64.exe" @@ -53,3 +54,4 @@ elif sys.platform == "linux": # /home/eli/.local/share/godot/templates/ GODOT_TEMPLATES_PATH = os.path.join( Path.home(), f".local/share/godot/templates/{GODOT_VERSION}.{GODOT_RELEASE_TYPE}") + diff --git a/Tools/download_ffmpeg.py b/Tools/download_ffmpeg.py index cd48ac63..959bfd15 100644 --- a/Tools/download_ffmpeg.py +++ b/Tools/download_ffmpeg.py @@ -1,14 +1,17 @@ #!/usr/bin/python3 # SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only from fileinput import filename +import sys from zipfile import ZipFile import platform from urllib.request import urlopen +import subprocess import os import defines from shutil import move, rmtree from util import cd_repo_root_path from sys import stdout +from defines import FFMPEG_VERSION stdout.reconfigure(encoding='utf-8') @@ -99,13 +102,44 @@ def download_prebuild_ffmpeg_windows(extraction_path: str): extract_zip_executables(extraction_path, ffmpeg_path_and_filename) -def execute(): +def execute() ->bool: # Make sure the script is always started from the same folder root_path = cd_repo_root_path() extraction_path = os.path.join(root_path, "ThirdParty/ffmpeg") + ffmpeg_binary_path = os.path.join(extraction_path, "ffmpeg") # Adjust this if FFmpeg binary is inside another subdirectory + + if sys.platform == "win32": + ffmpeg_binary_path += ".exe" + + # Check if ffmpeg is already installed and matches the required version + if os.path.isfile(ffmpeg_binary_path): + result = subprocess.run([ffmpeg_binary_path, "-version"], capture_output=True, text=True) + output = result.stdout + version_line = next((line for line in output.split('\n') if 'ffmpeg version' in line), None) + if version_line: + installed_version = version_line.split(' ')[2].split('-')[0] + if installed_version == FFMPEG_VERSION: + print(f"FFmpeg version {installed_version} is already installed.") + return True + else: + print(f"FFmpeg version {installed_version} found, but version {FFMPEG_VERSION} is required.") + + try: + if os.path.exists(extraction_path): + rmtree(extraction_path) + print("Directory removed successfully.") + except Exception as e: + print(f"An error occurred while trying to remove the directory: {str(e)}") + return False + + try: + if os.path.exists(extraction_path): + rmtree(extraction_path) + print("Directory removed successfully.") + except Exception as e: + print(f"An error occurred while trying to remove the directory: {str(e)}") + return False - if os.path.exists(extraction_path): - rmtree(extraction_path) os.makedirs(extraction_path) @@ -113,6 +147,8 @@ def execute(): download_prebuild_ffmpeg_windows(extraction_path) elif platform.system() == "Darwin": download_prebuild_ffmpeg_mac(extraction_path) + + return True if __name__ == "__main__": diff --git a/Tools/setup.py b/Tools/setup.py index 36006514..b75811fc 100755 --- a/Tools/setup.py +++ b/Tools/setup.py @@ -114,11 +114,13 @@ def main(): project_source_parent_path = root_path.joinpath("../").resolve() vcpkg_path = project_source_parent_path.joinpath("vcpkg").resolve() vcpkg_packages_list = defines.VCPKG_BASE_PACKAGES - if not args.skip_aqt: - setup_qt() - download_ffmpeg.execute() - setup_godot.execute() + if not setup_godot.execute(): + raise RuntimeError("Unable to download godot") + + if not download_ffmpeg.execute(): + raise RuntimeError("Unable to download ffmpeg") + if system() == "Windows": vcpkg_command = "vcpkg.exe" @@ -163,6 +165,8 @@ def main(): execute( f"{vcpkg_command} install {vcpkg_packages} --triplet {triplet} --recurse", vcpkg_path, False) + if not args.skip_aqt: + setup_qt() if __name__ == "__main__": main() diff --git a/Tools/setup_godot.py b/Tools/setup_godot.py index 3940a157..24150ee9 100644 --- a/Tools/setup_godot.py +++ b/Tools/setup_godot.py @@ -1,59 +1,112 @@ #!/usr/bin/python3 # SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only -import requests -import zipfile -import platform +import os +import sys +import shutil +import util from pathlib import Path -from defines import GODOT_VERSION -from util import repo_root_path # Assuming util.py exists and has repo_root_path() +import defines +import util + +def download_godot(version: str, exe_zip_filename: str, export_templates: str, download_destination_path: str) -> bool: + # https://downloads.tuxfamily.org/godotengine/4.2/beta4/Godot_v4.2-beta4_win64.exe.zip + # https://downloads.tuxfamily.org/godotengine/4.2/Godot_v4.2-beta4_win64.exe.zip + download_export_templates = f"{defines.GODOT_DOWNLOAD_SERVER}/{version}/{defines.GODOT_RELEASE_TYPE}/{export_templates}" + exe_destination_filepath = os.path.join( + download_destination_path, exe_zip_filename) + export_templates_destination_path = os.path.join( + download_destination_path, export_templates) + + # Godot adds ".stable" to the folder names for full releases: "AppData/Roaming/Godot/templates/3.4.stable": + print(f"Downloading Godot from {defines.GODOT_DOWNLOAD_SERVER}/") + download_link = f"{defines.GODOT_DOWNLOAD_SERVER}/{version}/{defines.GODOT_RELEASE_TYPE}/{exe_zip_filename}" + util.download(download_link, exe_destination_filepath, False) + util.download(download_export_templates, + export_templates_destination_path, False) + + return True -def execute(): +def unzip_godot(exe_zip_filepath: str, export_templates_filepath: str, destination_path: str) -> bool: + print("Unzip Godot") + util.unzip(exe_zip_filepath, destination_path) + + # The export templates contain a templates subfolder in which the content is. This is bad because it clashes + # with the folder structure where the version comes after: AppData\Roaming\Godot\templates\3.3.4.stable + # Rename: AppData\Roaming\Godot\templates\templates + # to : AppData\Roaming\Godot\templates\3.4.stable + godot_templates_dir = "" + if sys.platform == "win32": + godot_templates_dir = os.path.join( + os.getenv('APPDATA'), "Godot/templates/") + elif sys.platform == "linux": + godot_templates_dir = os.path.join( + str(Path.home()), ".local/share/godot/templates/") + os.makedirs(godot_templates_dir, exist_ok=True) + export_templates_destination_version = f"{godot_templates_dir}/{defines.GODOT_VERSION}.{defines.GODOT_RELEASE_TYPE}" + + # Remove previous folder + if os.path.exists(export_templates_destination_version): + print(f"Remove previous export templates folder: {export_templates_destination_version}") + shutil.rmtree(export_templates_destination_version) + + util.unzip(export_templates_filepath, godot_templates_dir) + os.rename(os.path.join(godot_templates_dir, "templates"), + export_templates_destination_version) + + print(f"Remove {exe_zip_filepath}") + try: + os.remove(exe_zip_filepath) + except OSError as error: + print(f"Error deleting file: {error}") + return False + + print(f"Remove {export_templates_filepath}") + try: + os.remove(export_templates_filepath) + except OSError as error: + print(f"Error deleting file: {error}") + return False + + return True + + +def setup_godot() -> bool: + print(f"Set up GODOT version {defines.GODOT_VERSION} {defines.GODOT_RELEASE_TYPE}") + destination_path = os.path.join(defines.THIRDPATH_PATH, "Godot") + export_templates = f"Godot_v{defines.GODOT_VERSION}-{defines.GODOT_RELEASE_TYPE}_export_templates.tpz" + export_templates_filepath = os.path.join( + destination_path, export_templates) + exe_zip_filename = defines.GODOT_EDITOR_EXECUTABLE + '.zip' + exe_zip_filepath = os.path.join(destination_path, exe_zip_filename) + download_godot(defines.GODOT_VERSION, exe_zip_filename, + export_templates, destination_path) + if not unzip_godot(exe_zip_filepath, export_templates_filepath, destination_path): + return False + + # Linux needs to change file permission to be able to run godot + if sys.platform == "linux": + execute(f"chmod +x {defines.GODOT_EDITOR_EXECUTABLE}", + destination_path, False) + + return True + + +def execute() -> bool: # Assuming repo_root_path() returns the git repo root path - root_path = Path(repo_root_path()) - godot_path = root_path / "Tools" / "Apps" / "Godot" + repo_path = Path(util.repo_root_path()) + godot_path = repo_path / "ThirdParty" / "Godot" # Create the directory if it doesn't exist godot_path.mkdir(parents=True, exist_ok=True) # Check if Godot executable already exists for file in godot_path.iterdir(): - if GODOT_VERSION in str(file): - print(f"Godot v{GODOT_VERSION} already exists.") - return - - # Determine OS type - os_type = platform.system().lower() - if os_type == "windows": - os_type = "win64.exe" - elif os_type == "linux": - os_type = "linux.x86_64" - elif os_type == "darwin": # macOS - os_type = "macos.universal" - else: - print("Unsupported OS") - return - - # Download Godot - base_url = "https://github.com/godotengine/godot/releases/download" - file_name = f"Godot_v{GODOT_VERSION}-stable_{os_type}.zip" - url = f"{base_url}/{GODOT_VERSION}-stable/{file_name}" - - response = requests.get(url) - if response.status_code == 200: - download_path = godot_path / file_name - download_path.write_bytes(response.content) - - # Extract ZIP file - with zipfile.ZipFile(download_path, 'r') as zip_ref: - zip_ref.extractall(godot_path) - - # Delete ZIP file - download_path.unlink() - print(f"Successfully installed Godot v{GODOT_VERSION}") - else: - print(f"Failed to download Godot v{GODOT_VERSION} for {os_type}") - + if defines.GODOT_VERSION in str(file): + print(f"Godot v{defines.GODOT_VERSION} already exists.") + return True + + return setup_godot() if __name__ == "__main__": execute() diff --git a/Tools/util.py b/Tools/util.py index 5a24cca1..0f00b965 100644 --- a/Tools/util.py +++ b/Tools/util.py @@ -9,6 +9,27 @@ import os import re import subprocess from sys import stdout +import zipfile +import urllib.request +import sys +import ssl + +def progress(count: int, block_size: int, total_size: int): + percent = int(count * block_size * 100 / total_size) + sys.stdout.write("\rDownload: {}%".format(percent)) + sys.stdout.flush() + +# disable broken progress bar in CI +def download(url: str, filename: str, show_progress: bool = True): + # This is needed for downloading from https sites + # see https://programmerah.com/python-error-certificate-verify-failed-certificate-has-expired-40374/ + ssl._create_default_https_context = ssl._create_unverified_context + + if show_progress: + urllib.request.urlretrieve(url, filename, progress) + else: + urllib.request.urlretrieve(url, filename) + stdout.reconfigure(encoding='utf-8') @@ -42,6 +63,11 @@ def repo_root_path() -> str: return os.path.realpath(path) +def workspace_path() -> str: + # One folder above the repo + path = os.path.join(repo_root_path(), "../") + return os.path.realpath(path) + def cd_repo_root_path() -> str: # Make sure the script is always started from the same # ScreenPlay root folder @@ -144,3 +170,11 @@ def semver_to_string(semver_dict): if semver_dict['pre_release']: version_str += f"-{semver_dict['pre_release']}" return version_str + + +def unzip(zip_path: str, destination_path: str, specific_file: str = None): + with zipfile.ZipFile(zip_path, 'r') as zip_ref: + if specific_file: + zip_ref.extract(specific_file, path=destination_path) + else: + zip_ref.extractall(path=destination_path) \ No newline at end of file