1
0
mirror of https://gitlab.com/kelteseth/ScreenPlay.git synced 2024-11-06 19:12:30 +01:00

Merge branch '173-update-cmake-versioning-and-add-ci-step-for-screenplay-releases' into 'master'

Resolve "Update CMake Versioning and Add CI Step for ScreenPlay Releases"

Closes #173

See merge request kelteseth/ScreenPlay!107
This commit is contained in:
Elias Steurer 2023-08-17 18:45:15 +00:00
commit f052c43d66
13 changed files with 373 additions and 201 deletions

View File

@ -1,118 +1,19 @@
include:
- ".gitlab/ci/base_jobs.yml"
- ".gitlab/ci/build_jobs.yml"
- ".gitlab/ci/build_release_jobs.yml"
- ".gitlab/ci/check_jobs.yml"
stages: stages:
# None Steam build for every commit
- build - build
# Steam build for every commit
- build_steam
# Git release tag builds
- release_build
# Checks for source code formattings
- check - 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 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: documentation:
stage: .post stage: .post
script: script:

46
.gitlab/ci/base_jobs.yml Normal file
View File

@ -0,0 +1,46 @@
.base_windows_build:
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:
before_script:
# Otherwise libglib2 needs interaction
- export DEBIAN_FRONTEND=noninteractive
- apt update -y
- apt install 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:
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/

41
.gitlab/ci/build_jobs.yml Normal file
View File

@ -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

View File

@ -0,0 +1,35 @@
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/bin
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-Installer.exe
- build-x64-windows-release/ScreenPlay-$CI_COMMIT_TAG-x64-windows-release.zip
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.app

16
.gitlab/ci/check_jobs.yml Normal file
View File

@ -0,0 +1,16 @@
formatting:
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 clang_format.py
- python cmake_format.py

12
.vscode/tasks.json vendored
View File

@ -102,16 +102,16 @@
"osx": { "osx": {
"args": [ "args": [
"build.py", "build.py",
"-type=release", "--type=release",
"-deploy-version", "--deploy-version",
"-steam" "--steam"
] ]
}, },
"args": [ "args": [
"build.py", "build.py",
"-type=release", "--type=release",
"-deploy-version", "--deploy-version",
"-steam" "--steam"
] ]
}, },
{ {

View File

@ -2,6 +2,7 @@ project(CMake)
set(FILES set(FILES
CMakeVariables.h.in CMakeVariables.h.in
GetProjectVersion.cmake
GenerateCMakeVariableHeader.cmake GenerateCMakeVariableHeader.cmake
CopyRecursive.cmake CopyRecursive.cmake
CreateIFWInstaller.cmake) CreateIFWInstaller.cmake)

View File

@ -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()

View File

@ -1,8 +1,12 @@
cmake_minimum_required(VERSION 3.23.0) 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( project(
ScreenPlay ScreenPlay
VERSION 0.15.0 VERSION ${PROJECT_VERSION}
DESCRIPTION "Modern, Cross Plattform, Live Wallpaper, Widgets and AppDrawer!" DESCRIPTION "Modern, Cross Plattform, Live Wallpaper, Widgets and AppDrawer!"
HOMEPAGE_URL "https://screen-play.app/" HOMEPAGE_URL "https://screen-play.app/"
LANGUAGES CXX) LANGUAGES CXX)
@ -21,7 +25,6 @@ endif()
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD 20)
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake" ${CMAKE_MODULE_PATH})
set(THIRD_PARTY_PATH "${CMAKE_CURRENT_SOURCE_DIR}/ThirdParty/") set(THIRD_PARTY_PATH "${CMAKE_CURRENT_SOURCE_DIR}/ThirdParty/")
option(OSX_BUNDLE "Enable distribution macOS bundle" OFF) option(OSX_BUNDLE "Enable distribution macOS bundle" OFF)
@ -136,18 +139,19 @@ if(${SCREENPLAY_INSTALLER} AND NOT APPLE)
include(${CMAKE_CURRENT_SOURCE_DIR}/CMake/CreateIFWInstaller.cmake) include(${CMAKE_CURRENT_SOURCE_DIR}/CMake/CreateIFWInstaller.cmake)
endif() endif()
message(STATUS "[CPP DEFINE] DEPLOY_VERSION = ${DEPLOY_VERSION}") message(STATUS "[PROJECT] PROJECT_VERSION = ${PROJECT_VERSION}")
message(STATUS "[CPP DEFINE] SOURCE_DIR = ${CMAKE_CURRENT_SOURCE_DIR}") message(STATUS "[PROJECT] CMAKE_VERSION = ${CMAKE_VERSION}")
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] SCREENPLAY_QML_MODULES_PATH = ${SCREENPLAY_QML_MODULES_PATH}") message(STATUS "[PROJECT] SCREENPLAY_QML_MODULES_PATH = ${SCREENPLAY_QML_MODULES_PATH}")
message(STATUS "[PROJECT] CMAKE_TOOLCHAIN_FILE = ${CMAKE_TOOLCHAIN_FILE}") message(STATUS "[PROJECT] CMAKE_TOOLCHAIN_FILE = ${CMAKE_TOOLCHAIN_FILE}")
message(STATUS "[PROJECT] VCPKG_PATH = ${VCPKG_PATH}") message(STATUS "[PROJECT] VCPKG_PATH = ${VCPKG_PATH}")
message(STATUS "[PROJECT] VCPKG_TARGET_TRIPLET = ${VCPKG_TARGET_TRIPLET}") message(STATUS "[PROJECT] VCPKG_TARGET_TRIPLET = ${VCPKG_TARGET_TRIPLET}")
message(STATUS "[PROJECT] CMAKE_PREFIX_PATH = ${CMAKE_PREFIX_PATH}") 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}")

View File

@ -11,7 +11,7 @@ import defines
from typing import Tuple from typing import Tuple
from pathlib import Path from pathlib import Path
import macos_sign 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 from sys import stdout
stdout.reconfigure(encoding='utf-8') stdout.reconfigure(encoding='utf-8')
@ -25,7 +25,7 @@ def clean_build_dir(build_dir):
build_dir.mkdir(parents=True, exist_ok=True) build_dir.mkdir(parents=True, exist_ok=True)
class BuildResult: class BuildResult:
# Windows example with absolute paths: # Windows example with absolute paths:
# [...]/build-x64-windows-release/ # [...]/build-x64-windows-release/
build: Path build: Path
@ -42,6 +42,7 @@ class BuildResult:
# x64, arm64, universal # x64, arm64, universal
build_arch: str build_arch: str
class BuildConfig: class BuildConfig:
root_path: str root_path: str
cmake_osx_architectures: str cmake_osx_architectures: str
@ -51,8 +52,8 @@ class BuildConfig:
package_command: str package_command: str
executable_file_ending: str executable_file_ending: str
# qt_* use either aqt or from the maintenance tool # qt_* use either aqt or from the maintenance tool
qt_path: str # C:\Qt qt_path: str # C:\Qt
qt_bin_path: str # C:\Qt\6.3.2\msvc2019_64 qt_bin_path: str # C:\Qt\6.3.2\msvc2019_64
qt_version: str qt_version: str
qt_ifw_version: str qt_ifw_version: str
ifw_root_path: str ifw_root_path: str
@ -90,12 +91,12 @@ def execute(
# 3rd party tools like the crashreporter create local # 3rd party tools like the crashreporter create local
# temporary files in the build directory. # temporary files in the build directory.
clean_build_dir(build_config.build_folder) clean_build_dir(build_config.build_folder)
# Runs cmake configure and cmake build # Runs cmake configure and cmake build
step_time = time.time() step_time = time.time()
build_result = build(build_config, build_result) build_result = build(build_config, build_result)
build_duration = time.time() - step_time build_duration = time.time() - step_time
#print(f"⏱️ build_duration (for {build_config.build_architecture}): {build_duration}s") # print(f"⏱️ build_duration (for {build_config.build_architecture}): {build_duration}s")
# Copies all needed libraries and assets into the bin folder # Copies all needed libraries and assets into the bin folder
step_time = time.time() step_time = time.time()
@ -122,9 +123,11 @@ def execute(
# Print BuildConfig & BuildResult member for easier debugging # Print BuildConfig & BuildResult member for easier debugging
print("\n🆗 BuildResult:") 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("\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 return build_result
@ -134,10 +137,13 @@ def setup(build_config: BuildConfig) -> Tuple[BuildConfig, BuildResult]:
build_config.qt_path = defines.QT_PATH build_config.qt_path = defines.QT_PATH
if not build_config.qt_path.exists(): 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) exit(2)
build_config.qt_bin_path = Path(build_config.qt_path).joinpath(f"{build_config.qt_version}/{defines.QT_PLATFORM}").resolve() build_config.qt_bin_path = Path(build_config.qt_path).joinpath(
build_config.ifw_root_path = Path(f"{build_config.qt_path}/Tools/QtInstallerFramework/{build_config.qt_ifw_version}").resolve() 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": if platform.system() == "Windows":
build_config.cmake_target_triplet = "x64-windows" build_config.cmake_target_triplet = "x64-windows"
@ -157,10 +163,10 @@ def setup(build_config: BuildConfig) -> Tuple[BuildConfig, BuildResult]:
build_config.cmake_target_triplet = "64-osx-universal" build_config.cmake_target_triplet = "64-osx-universal"
build_config.executable_file_ending = ".app" build_config.executable_file_ending = ".app"
# NO f string we fill it later! # 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_qt_packages = f"mac desktop {build_config.qt_version} clang_64 -m all"
build_config.aqt_install_tool_packages = "mac desktop tools_ifw" build_config.aqt_install_tool_packages = "mac desktop tools_ifw"
elif platform.system() == "Linux": elif platform.system() == "Linux":
build_config.cmake_target_triplet = "x64-linux" build_config.cmake_target_triplet = "x64-linux"
build_config.executable_file_ending = "" build_config.executable_file_ending = ""
@ -171,21 +177,27 @@ def setup(build_config: BuildConfig) -> Tuple[BuildConfig, BuildResult]:
"Unsupported platform, ScreenPlay only supports Windows, macOS and Linux.") "Unsupported platform, ScreenPlay only supports Windows, macOS and Linux.")
# Prepare # 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"cmake_toolchain_file: {build_config.cmake_toolchain_file}")
print(f"Starting build with type {build_config.build_type}.") 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 # 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") build_config.bin_dir = build_config.build_folder.joinpath("bin")
if platform.system() == "Windows": 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": 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": 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 return build_config, build_result
@ -201,7 +213,7 @@ def build(build_config: BuildConfig, build_result: BuildResult) -> BuildResult:
-DSCREENPLAY_DEPLOY={build_config.build_deploy} \ -DSCREENPLAY_DEPLOY={build_config.build_deploy} \
-DSCREENPLAY_INSTALLER={build_config.create_installer} \ -DSCREENPLAY_INSTALLER={build_config.create_installer} \
-DSCREENPLAY_IFW_ROOT:STRING={build_config.ifw_root_path} \ -DSCREENPLAY_IFW_ROOT:STRING={build_config.ifw_root_path} \
-G "CodeBlocks - Ninja" \ -G "Ninja" \
-B.' -B.'
print(f"\n⚙️ CMake configure:\n", cmake_configure_command.replace( print(f"\n⚙️ CMake configure:\n", cmake_configure_command.replace(
@ -220,21 +232,26 @@ def package(build_config: BuildConfig):
if platform.system() == "Darwin": if platform.system() == "Darwin":
# Make sure to reset to tools path # Make sure to reset to tools path
os.chdir(repo_root_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)\" # -sign-for-notarization=\"Developer ID Application: Elias Steurer (V887LHYKRH)\"
build_bin_dir = Path(repo_root_path()).joinpath(f"{build_config.build_folder}/bin/") 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 "
cwd = Path(repo_root_path()).joinpath(f"{build_bin_dir}/ScreenPlay.app/Contents/MacOS/") 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() qt_bin_path = Path(defines.QT_BIN_PATH).resolve()
source_path = Path(repo_root_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,
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) 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="ScreenPlayWidget"), 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): if (build_config.sign_osx):
print(f"Sign binary at: {build_config.bin_dir}") print(f"Sign binary at: {build_config.bin_dir}")
macos_sign.sign(build_config=build_config) macos_sign.sign(build_config=build_config)
if platform.system() == "Windows": if platform.system() == "Windows":
print("Executing deploy commands...") print("Executing deploy commands...")
run(build_config.package_command.format( run(build_config.package_command.format(
@ -291,8 +308,6 @@ def package(build_config: BuildConfig):
shutil.copy(str(file), str(build_config.bin_dir)) shutil.copy(str(file), str(build_config.bin_dir))
print("Copied %s" % file) print("Copied %s" % file)
# Some dlls like openssl do no longer get copied automatically. # Some dlls like openssl do no longer get copied automatically.
# Lets just copy all of them into bin. # Lets just copy all of them into bin.
if platform.system() == "Windows": if platform.system() == "Windows":
@ -326,6 +341,7 @@ def build_installer(build_config: BuildConfig, build_result: BuildResult):
print("Running cpack at: ", os.getcwd()) print("Running cpack at: ", os.getcwd())
run("cpack", cwd=build_config.build_folder) run("cpack", cwd=build_config.build_folder)
def zip(build_config: BuildConfig, build_result: BuildResult) -> BuildResult: 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" 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) build_result.build_zip = Path(build_result.build).joinpath(zipName)
@ -346,9 +362,11 @@ def zip(build_config: BuildConfig, build_result: BuildResult) -> BuildResult:
# Some weird company firewalls do not allow direct .exe downloads # Some weird company firewalls do not allow direct .exe downloads
# lets just zip the installer lol # lets just zip the installer lol
if build_config.create_installer == "ON": 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}") 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 return build_result
@ -357,35 +375,47 @@ if __name__ == "__main__":
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description='Build and Package ScreenPlay') 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") 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") 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.") 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/.") 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.") 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.") 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.") 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.") 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!") 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") 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() args = parser.parse_args()
qt_version = defines.QT_VERSION qt_version = defines.QT_VERSION
screenplay_version = defines.SCREENPLAY_VERSION
qt_ifw_version = defines.QT_IFW_VERSION # Not yet used. qt_ifw_version = defines.QT_IFW_VERSION # Not yet used.
qt_version_overwrite: str qt_version_overwrite: str
use_aqt = False 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: if args.qt_version_overwrite:
qt_version = args.qt_version_overwrite qt_version = args.qt_version_overwrite
print("Using Qt version {qt_version}") print("Using Qt version {qt_version}")

View File

@ -1,9 +1,7 @@
#!/usr/bin/python3 #!/usr/bin/python3
# SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only # SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only
import steam_publish import steam_publish
import shutil
import sys import sys
import macos_sign
import argparse import argparse
import os import os
import build import build
@ -11,18 +9,26 @@ from pathlib import Path
import platform import platform
import paramiko import paramiko
import defines import defines
from util import sftp_exists, run, repo_root_path from util import sftp_exists, get_latest_git_tag, parse_semver, semver_to_string
from sys import stdout from sys import stdout
stdout.reconfigure(encoding='utf-8') stdout.reconfigure(encoding='utf-8')
if __name__ == "__main__": if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Build and Package ScreenPlay') parser = argparse.ArgumentParser(
parser.add_argument('-skip_publish', '-skp', action="store_true", dest="skip_publish", default=False, help="skip publish") description='Build and Package ScreenPlay')
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('--skip_steam_publish', '-skstp', action="store_true",
parser.add_argument('-steam_password', '-sp', action="store", dest="steam_password", help="Steam password") dest="skip_publish", default=False, help="skip publish")
parser.add_argument('-hosting_username','-hu', action="store", dest="hosting_username", help="ssh username") parser.add_argument('--skip_getspde_publish', '-skgsp', action="store_true",
parser.add_argument('-hosting_password', '-hp', action="store", dest="hosting_password", help="ssh password") dest="skip_getspde_publish", default=False, help="skip getsp.de 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() args = parser.parse_args()
# Script needs to run in the tools folder # Script needs to run in the tools folder
@ -31,10 +37,23 @@ if __name__ == "__main__":
root_path = tools_path.parent root_path = tools_path.parent
print(f"Set root directory to: {root_path}") 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 = build.BuildResult() build_result = build.BuildResult()
build_config = build.BuildConfig() build_config = build.BuildConfig()
build_config.screenplay_version = defines.SCREENPLAY_VERSION
build_config.qt_version = defines.QT_VERSION build_config.qt_version = defines.QT_VERSION
build_config.qt_ifw_version = defines.QT_IFW_VERSION build_config.qt_ifw_version = defines.QT_IFW_VERSION
build_config.build_steam = "ON" build_config.build_steam = "ON"
@ -42,6 +61,7 @@ if __name__ == "__main__":
build_config.build_deploy = "ON" build_config.build_deploy = "ON"
build_config.create_installer = "ON" build_config.create_installer = "ON"
build_config.build_type = "release" build_config.build_type = "release"
build_config.screenplay_version = screenplay_version
if platform.system() == "Darwin" and not args.skip_build: if platform.system() == "Darwin" and not args.skip_build:
# We do not yet support a standalone osx installer # We do not yet support a standalone osx installer
@ -54,21 +74,21 @@ if __name__ == "__main__":
# This will build both arm64 and x64 and sign the unversal binary # This will build both arm64 and x64 and sign the unversal binary
build_result = build.execute(build_config) build_result = build.execute(build_config)
if platform.system() == "Windows" and not args.skip_build: if platform.system() == "Windows" and not args.skip_build:
build_config.build_architecture = "x64" build_config.build_architecture = "x64"
if not args.skip_publish: if not args.skip_getspde_publish:
# Steamless version first # Steamless version first
build_config.build_steam = "OFF" build_config.build_steam = "OFF"
build_result = build.execute(build_config) build_result = build.execute(build_config)
ssh = paramiko.SSHClient() ssh = paramiko.SSHClient()
ssh.load_system_host_keys() ssh.load_system_host_keys()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('kelteseth.com', username=args.hosting_username, password=args.hosting_password) ssh.connect('kelteseth.com', username=args.hosting_username,
password=args.hosting_password)
sftp = ssh.open_sftp() sftp = ssh.open_sftp()
release_folder = "/kelteseth_com/public/releases/" + build_config.screenplay_version + "/" release_folder = "/getsp.de/" + build_config.screenplay_version + "/"
if sftp_exists(sftp,release_folder): if sftp_exists(sftp, release_folder):
remoteFiles = sftp.listdir(path=release_folder) remoteFiles = sftp.listdir(path=release_folder)
for file in remoteFiles: for file in remoteFiles:
print(f"Delte old: {release_folder+file}") print(f"Delte old: {release_folder+file}")
@ -77,10 +97,14 @@ if __name__ == "__main__":
sftp.mkdir(release_folder) sftp.mkdir(release_folder)
print("Uploading files...") print("Uploading files...")
sftp.put(build_result.build_zip, release_folder + str(build_result.build_zip.name)) sftp.put(build_result.build_zip, release_folder +
sftp.put(build_result.installer, release_folder + str(build_result.installer.name)) str(build_result.build_zip.name))
sftp.put(build_result.installer_zip,release_folder + str(build_result.installer_zip.name)) sftp.put(build_result.installer, release_folder +
sftp.put(build_result.build_hash, release_folder + str(build_result.build_hash.name)) 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() sftp.close()
ssh.close() ssh.close()
@ -90,14 +114,14 @@ if __name__ == "__main__":
build_config.create_installer = "OFF" build_config.create_installer = "OFF"
build_result = build.execute(build_config) build_result = build.execute(build_config)
if args.skip_publish: if args.skip_steam_publish:
print("Skip publishing.") print("Skip steam publishing.")
sys.exit(0) sys.exit(0)
if args.steam_password is None: if args.steam_password is None:
print("Steam password is required.") print("Steam password is required.")
sys.exit(1) sys.exit(1)
# Make sure to reset to tools path # Make sure to reset to tools path
os.chdir(tools_path) os.chdir(tools_path)
steam_publish.publish( steam_publish.publish(

View File

@ -18,7 +18,6 @@ elif sys.platform == "linux":
OS = "linux" OS = "linux"
QT_PLATFORM = "gcc_64" QT_PLATFORM = "gcc_64"
SCREENPLAY_VERSION = "0.15.1"
QT_PATH = path = Path(os.path.join( QT_PATH = path = Path(os.path.join(
os.path.realpath(__file__), "../../../aqt")).resolve() os.path.realpath(__file__), "../../../aqt")).resolve()
QT_VERSION = "6.5.2" QT_VERSION = "6.5.2"

View File

@ -6,11 +6,13 @@ from pathlib import Path
from os import chdir from os import chdir
from concurrent.futures import ThreadPoolExecutor from concurrent.futures import ThreadPoolExecutor
import os import os
import re
import subprocess import subprocess
from sys import stdout from sys import stdout
stdout.reconfigure(encoding='utf-8') stdout.reconfigure(encoding='utf-8')
def sftp_exists(sftp, path) -> bool: def sftp_exists(sftp, path) -> bool:
try: try:
sftp.stat(path) sftp.stat(path)
@ -24,6 +26,7 @@ def run(cmd, cwd=Path.cwd()):
if result.returncode != 0: if result.returncode != 0:
raise RuntimeError(f"Failed to execute {cmd}") raise RuntimeError(f"Failed to execute {cmd}")
def run_and_capture_output(cmd, cwd=Path.cwd()) -> str: def run_and_capture_output(cmd, cwd=Path.cwd()) -> str:
result = subprocess.run(cmd, shell=True, cwd=cwd, stdout=subprocess.PIPE) result = subprocess.run(cmd, shell=True, cwd=cwd, stdout=subprocess.PIPE)
if result.returncode != 0: if result.returncode != 0:
@ -31,14 +34,16 @@ def run_and_capture_output(cmd, cwd=Path.cwd()) -> str:
if result.stdout is not None: if result.stdout is not None:
return str(result.stdout.decode('utf-8')) return str(result.stdout.decode('utf-8'))
return "" return ""
def repo_root_path() -> str: def repo_root_path() -> str:
# Root dir of the repository # Root dir of the repository
path = os.path.join(os.path.realpath(__file__), "../../") path = os.path.join(os.path.realpath(__file__), "../../")
return os.path.realpath(path) return os.path.realpath(path)
def cd_repo_root_path() -> str: 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 # ScreenPlay root folder
root_path = Path.cwd() root_path = Path.cwd()
if root_path.name == "Tools": if root_path.name == "Tools":
@ -47,6 +52,7 @@ def cd_repo_root_path() -> str:
chdir(root_path) chdir(root_path)
return root_path return root_path
def sha256(fname) -> str: def sha256(fname) -> str:
hash_sha256 = hashlib.sha256() hash_sha256 = hashlib.sha256()
with open(fname, "rb") as f: with open(fname, "rb") as f:
@ -55,7 +61,6 @@ def sha256(fname) -> str:
return hash_sha256.hexdigest() return hash_sha256.hexdigest()
def zipdir(path, ziph): def zipdir(path, ziph):
# ziph is zipfile handle # ziph is zipfile handle
for root, dirs, files in os.walk(path): for root, dirs, files in os.walk(path):
@ -102,3 +107,40 @@ def get_vs_env_dict():
raise ValueError(stderr.decode("mbcs")) raise ValueError(stderr.decode("mbcs"))
output = stdout.decode("mbcs").split("\r\n") 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) 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.0-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-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