1
0
mirror of https://gitlab.com/kelteseth/ScreenPlay.git synced 2024-11-07 03:22:33 +01:00

Rewrite of build.py to use classes and functions

2 classes that old the data that later will be
used for the ftp upload and other tools
This commit is contained in:
Elias Steurer 2022-07-24 17:56:00 +02:00
parent 3740ab9789
commit f5bb79d160
4 changed files with 388 additions and 260 deletions

View File

@ -6,27 +6,18 @@ import platform
import shutil import shutil
import argparse import argparse
import time import time
from typing import Tuple
import zipfile import zipfile
from shutil import copytree from shutil import copytree
from pathlib import Path from pathlib import Path
from concurrent.futures import ThreadPoolExecutor
from datetime import datetime from datetime import datetime
from util import sha256, cd_repo_root_path, zipdir, run
SCREENPLAY_VERSION = "0.15.0-RC1"
def zipdir(path, ziph):
# ziph is zipfile handle
for root, dirs, files in os.walk(path):
for file in files:
ziph.write(os.path.join(root, file),
os.path.relpath(os.path.join(root, file),
os.path.join(path, '..')))
# Based on https://gist.github.com/l2m2/0d3146c53c767841c6ba8c4edbeb4c2c # Based on https://gist.github.com/l2m2/0d3146c53c767841c6ba8c4edbeb4c2c
def get_vs_env_dict(): def get_vs_env_dict():
vcvars = "" # We support 2019 or 2022 vcvars: str # We support 2019 or 2022
# Hardcoded VS path # Hardcoded VS path
# check if vcvars64.bat is available. # check if vcvars64.bat is available.
@ -55,13 +46,6 @@ def get_vs_env_dict():
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 run_io_tasks_in_parallel(tasks):
with ThreadPoolExecutor() as executor:
running_tasks = [executor.submit(task) for task in tasks]
for running_task in running_tasks:
running_task.result()
def clean_build_dir(build_dir): def clean_build_dir(build_dir):
if isinstance(build_dir, str): if isinstance(build_dir, str):
build_dir = Path(build_dir) build_dir = Path(build_dir)
@ -72,284 +56,402 @@ def clean_build_dir(build_dir):
build_dir.mkdir(parents=True, exist_ok=True) build_dir.mkdir(parents=True, exist_ok=True)
def run(cmd, cwd=Path.cwd()): class BuildResult: # Windows example with absolute paths:
result = subprocess.run(cmd, shell=True, cwd=cwd) build: Path # [...]/build-x64-windows-release/
if result.returncode != 0: binary: Path # [...]/build-x64-windows-release/bin
raise RuntimeError(f"Failed to execute {cmd}") # [...]/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.15.0-RC1-x64-windows-release.zip
build_zip: Path
# [...]/build-x64-windows-release/ScreenPlay-0.15.0-RC1-x64-windows-release.txt
build_hash: Path # sha256, needed for scoop
build_arch: str # x64, arm64, universal
def build( class BuildConfig:
qt_version: str, root_path: str
qt_ifw_version: str, cmake_osx_architectures: str
build_steam: str, cmake_target_triplet: str
build_tests: str, deploy_command: str
build_release: str, executable_file_ending: str
create_installer: str, qt_path: str
build_type: str, qt_bin_path: str
sign_build: str, qt_version: str
use_aqt: bool, qt_ifw_version: str
ifw_root_path: str
cmake_toolchain_file: str
use_aqt: bool
aqt_install_qt_packages: str
aqt_install_tool_packages: str
aqt_path: str
executable_file_ending: str
build_folder: str
bin_dir: str
sign_build: bool
screenplay_version: str
# CMake variables need str: "ON" or "OFF"
build_steam: str
build_tests: str
build_release: str
build_type: str
build_architecture: str build_architecture: str
): create_installer: str
def execute(
build_config: BuildConfig
) -> BuildResult:
# Make sure the script is always started from the same folder # Make sure the script is always started from the same folder
root_path = Path.cwd() build_config.root_path = cd_repo_root_path()
if root_path.name == "Tools":
root_path = root_path.parent
print(f"Change root directory to: {root_path}")
os.chdir(root_path)
aqt_path = "" build_result = BuildResult()
if use_aqt:
aqt_path = Path(f"{root_path}/../aqt/").resolve()
if not Path(aqt_path).exists(): # Sets all platform spesific paths, arguments etc.
setup_tuple = setup(build_config, build_result)
build_config = setup_tuple[0]
build_result = setup_tuple[1]
build_result.build = Path(build_config.build_folder)
build_result.binary = Path(build_config.bin_dir)
# Make sure to always delete everything first.
# 3rd party tools like the crashreporter create local
# temporary files in the build directory.
clean_build_dir(build_config.build_folder)
start_time = time.time()
# Runs cmake configure and cmake build
build_result = build(build_config, build_result)
# Copies all needed libraries and assets into the bin folder
deploy(build_config)
# Creates a Qt InstallerFrameWork (IFW) installer
if build_config.create_installer == "ON":
create_installer(build_config, build_result)
# Mac needs signed builds for user to run the app
if platform.system() == "Darwin" and build_config.sign_build:
sign(build_config)
# Create a zip file for scoop
build_result = zip(build_config, build_result)
print("Time taken: {}s".format(time.time() - start_time))
# Print BuildConfig & BuildResult member for easier debugging
print("BuildResult:\n")
print(' '.join("- %s: \t\t%s\n" % item for item in vars(build_result).items()))
print("BuildConfig:\n")
print(' '.join("- %s: \t\t%s\n" % item for item in vars(build_config).items()))
return build_result
def setup(build_config: BuildConfig, build_result: BuildResult) -> Tuple[BuildConfig, BuildResult]:
if build_config.use_aqt:
build_config.aqt_path = Path(
f"{build_config.root_path}/../aqt/").resolve()
if not Path(build_config.aqt_path).exists():
print( print(
f"aqt path does not exist at {aqt_path}. Please make sure you have installed aqt.") f"aqt path does not exist at {build_config.aqt_path}. Please make sure you have installed aqt.")
exit(2) exit(2)
# Set default to empty, because it is only used on mac
CMAKE_OSX_ARCHITECTURES: str = "" build_config.cmake_osx_architectures = ""
deploy_command: str = ""
executable_file_ending: str = ""
qt_path: str = ""
qt_bin_path: str = ""
aqt_install_qt_packages: str = ""
aqt_install_tool_packages: str = ""
cmake_target_triplet: str = ""
file_endings = [".ninja_deps", ".ninja", ".ninja_log", ".lib", ".a", ".exp",
".manifest", ".cmake", ".cbp", "CMakeCache.txt"]
if platform.system() == "Windows": if platform.system() == "Windows":
cmake_target_triplet = "x64-windows" build_config.cmake_target_triplet = "x64-windows"
windows_msvc = "msvc2019_64" build_config.executable_file_ending = ".exe"
executable_file_ending = ".exe" build_config.qt_path = build_config.aqt_path if build_config.use_aqt else Path(
qt_path = aqt_path if use_aqt else Path("C:/Qt") "C:/Qt")
qt_bin_path = aqt_path.joinpath(qt_version).joinpath( windows_msvc = "msvc2019_64" # This will change once prebuild Qt bins change
windows_msvc) if use_aqt else Path(f"C:/Qt/{qt_version}/{windows_msvc}") build_config.qt_bin_path = build_config.aqt_path.joinpath(build_config.qt_version).joinpath(
windows_msvc) if build_config.use_aqt else Path(f"C:/Qt/{build_config.qt_version}/{windows_msvc}")
vs_env_dict = get_vs_env_dict() vs_env_dict = get_vs_env_dict()
vs_env_dict["PATH"] = vs_env_dict["PATH"] + \ vs_env_dict["PATH"] = vs_env_dict["PATH"] + \
";" + str(qt_bin_path) + "\\bin" ";" + str(build_config.qt_bin_path) + "\\bin"
os.environ.update(vs_env_dict) os.environ.update(vs_env_dict)
deploy_command = "windeployqt.exe --{type} --qmldir ../../{app}/qml {app}{executable_file_ending}" # NO f string we fill it later!
build_config.deploy_command = "windeployqt.exe --{type} --qmldir ../../{app}/qml {app}{executable_file_ending}"
aqt_install_qt_packages = f"windows desktop {qt_version} win64_msvc2019_64 -m all" build_config.aqt_install_qt_packages = f"windows desktop {build_config.qt_version} win64_msvc2019_64 -m all"
aqt_install_tool_packages = "windows desktop tools_ifw" build_config.aqt_install_tool_packages = "windows desktop tools_ifw"
elif platform.system() == "Darwin": elif platform.system() == "Darwin":
if(build_architecture == "arm64"): if(build_config.build_architecture == "arm64"):
cmake_target_triplet = "arm64-osx" build_config.cmake_target_triplet = "arm64-osx"
CMAKE_OSX_ARCHITECTURES = "-DCMAKE_OSX_ARCHITECTURES=arm64" build_config.cmake_osx_architectures = "-DCMAKE_OSX_ARCHITECTURES=arm64"
elif(build_architecture == "x64"): elif(build_config.build_architecture == "x64"):
cmake_target_triplet = "x64-osx" build_config.cmake_target_triplet = "x64-osx"
CMAKE_OSX_ARCHITECTURES = "-DCMAKE_OSX_ARCHITECTURES=x86_64" build_config.cmake_osx_architectures = "-DCMAKE_OSX_ARCHITECTURES=x86_64"
else: else:
print("MISSING BUILD ARCH: SET arm64 or x64") print("MISSING BUILD ARCH: SET arm64 or x64")
exit(1) exit(1)
qt_path = aqt_path if use_aqt else Path("~/Qt/") build_config.qt_path = build_config.aqt_path if build_config.use_aqt else Path(
qt_bin_path = aqt_path.joinpath( "~/Qt/")
f"{qt_version}/macos") if use_aqt else Path(f"~/Qt/{qt_version}/macos") build_config.qt_bin_path = build_config.aqt_path.joinpath(
deploy_command = "{prefix_path}/bin/macdeployqt {app}.app -qmldir=../../{app}/qml -executable={app}.app/Contents/MacOS/{app}" f"{build_config.qt_version}/macos") if build_config.use_aqt else Path(f"~/Qt/{build_config.qt_version}/macos")
# NO f string we fill it later!
build_config.deploy_command = "{prefix_path}/bin/macdeployqt {app}.app -qmldir=../../{app}/qml -executable={app}.app/Contents/MacOS/{app}"
aqt_install_qt_packages = f"mac desktop {qt_version} clang_64 -m all" build_config.aqt_install_qt_packages = f"mac desktop {build_config.qt_version} clang_64 -m all"
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":
cmake_target_triplet = "x64-linux" build_config.cmake_target_triplet = "x64-linux"
qt_path = aqt_path if use_aqt else Path("~/Qt/") build_config.qt_path = build_config.aqt_path if build_config.use_aqt else Path(
qt_bin_path = aqt_path.joinpath( "~/Qt/")
f"{qt_version}/gcc_64") if use_aqt else Path(f"~/Qt/{qt_version}/gcc_64") build_config.qt_bin_path = build_config.aqt_path.joinpath(
aqt_install_qt_packages = f"linux desktop {qt_version} gcc_64 -m all" f"{build_config.qt_version}/gcc_64") if build_config.use_aqt else Path(f"~/Qt/{build_config.qt_version}/gcc_64")
aqt_install_tool_packages = "linux desktop tools_ifw" build_config.aqt_install_qt_packages = f"linux desktop {build_config.qt_version} gcc_64 -m all"
build_config.aqt_install_tool_packages = "linux desktop tools_ifw"
if shutil.which("cqtdeployer"): if shutil.which("cqtdeployer"):
deploy_command = "cqtdeployer -qmlDir ../../{app}/qml -bin {app}" # NO f string we fill it later!
build_config.deploy_command = "cqtdeployer -qmlDir ../../{app}/qml -bin {app}"
else: else:
print("cqtdeployer not available, build may be incomplete and incompatible with some distro (typically Ubuntu)") print("cqtdeployer not available, build may be incomplete and incompatible with some distro (typically Ubuntu)")
home_path = str(Path.home()) home_path = str(Path.home())
qt_bin_path = aqt_path.joinpath( build_config.qt_bin_path = build_config.aqt_path.joinpath(
f"{qt_version}/gcc_64") if use_aqt else Path(f"{home_path}/Qt/{qt_version}/gcc_64") f"{build_config.qt_version}/gcc_64") if build_config.use_aqt else Path(f"{home_path}/Qt/{build_config.qt_version}/gcc_64")
else: else:
raise NotImplementedError( raise NotImplementedError(
"Unsupported platform, ScreenPlay only supports Windows, macOS and Linux.") "Unsupported platform, ScreenPlay only supports Windows, macOS and Linux.")
# Default to QtMaintainance installation. # Default to QtMaintainance installation.
if use_aqt: if build_config.use_aqt:
print(f"qt_bin_path: {qt_bin_path}.") print(f"qt_bin_path: {build_config.qt_bin_path}.")
if not Path(aqt_path).exists(): if not Path(build_config.aqt_path).exists():
print( print(
f"aqt path does not exist at {aqt_path}. Installing now into...") f"aqt path does not exist at {build_config.aqt_path}. Installing now into...")
run(f"aqt install-qt -O ../aqt {aqt_install_qt_packages}", cwd=root_path) run(f"aqt install-qt -O ../aqt {build_config.aqt_install_qt_packages}",
cwd=build_config.root_path)
run( run(
f"aqt install-tool -O ../aqt {aqt_install_tool_packages}", cwd=root_path) f"aqt install-tool -O ../aqt {build_config.aqt_install_tool_packages}", cwd=build_config.root_path)
# Prepare # Prepare
cmake_toolchain_file = f"'{root_path}/../ScreenPlay-vcpkg/scripts/buildsystems/vcpkg.cmake'" build_config.cmake_toolchain_file = f"'{build_config.root_path}/../ScreenPlay-vcpkg/scripts/buildsystems/vcpkg.cmake'"
ifw_root_path = f"{qt_path}/Tools/QtInstallerFramework/{qt_ifw_version}" build_config.ifw_root_path = f"{build_config.qt_path}/Tools/QtInstallerFramework/{build_config.qt_ifw_version}"
print(f"cmake_toolchain_file: {cmake_toolchain_file}") print(f"cmake_toolchain_file: {build_config.cmake_toolchain_file}")
print( print(
f"Starting build with type {build_type}. Qt Version: {qt_version}. Root path: {root_path}") f"Starting build with type {build_config.build_type}. Qt Version: {build_config.qt_version}. Root path: {build_config.root_path}")
# Remove old build folder to before configuring to get rid of
# Remove old build folder to before configuring to get rid of # all cmake chaches
# all cmake chaches build_config.build_folder = build_config.root_path.joinpath(
build_folder = root_path.joinpath( f"build-{build_config.cmake_target_triplet}-{build_config.build_type}")
f"build-{cmake_target_triplet}-{build_type}") build_config.bin_dir = build_config.build_folder.joinpath("bin")
clean_build_dir(build_folder)
if platform.system() == "Windows":
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-Installer.dmg")
elif platform.system() == "Linux":
build_result.installer = Path(build_config.build_folder).joinpath(
"ScreenPlay-Installer.run")
return build_config, build_result
def build(build_config: BuildConfig, build_result: BuildResult) -> BuildResult:
cmake_configure_command = f'cmake ../ \ cmake_configure_command = f'cmake ../ \
{CMAKE_OSX_ARCHITECTURES} \ {build_config.cmake_osx_architectures} \
-DCMAKE_PREFIX_PATH={qt_bin_path} \ -DCMAKE_PREFIX_PATH={build_config.qt_bin_path} \
-DCMAKE_BUILD_TYPE={build_type} \ -DCMAKE_BUILD_TYPE={build_config.build_type} \
-DVCPKG_TARGET_TRIPLET={cmake_target_triplet} \ -DVCPKG_TARGET_TRIPLET={build_config.cmake_target_triplet} \
-DCMAKE_TOOLCHAIN_FILE={cmake_toolchain_file} \ -DCMAKE_TOOLCHAIN_FILE={build_config.cmake_toolchain_file} \
-DSCREENPLAY_STEAM={build_steam} \ -DSCREENPLAY_STEAM={build_config.build_steam} \
-DSCREENPLAY_TESTS={build_tests} \ -DSCREENPLAY_TESTS={build_config.build_tests} \
-DSCREENPLAY_RELEASE={build_release} \ -DSCREENPLAY_RELEASE={build_config.build_release} \
-DSCREENPLAY_INSTALLER={create_installer} \ -DSCREENPLAY_INSTALLER={build_config.create_installer} \
-DSCREENPLAY_IFW_ROOT:STRING={ifw_root_path} \ -DSCREENPLAY_IFW_ROOT:STRING={build_config.ifw_root_path} \
-G "CodeBlocks - Ninja" \ -G "CodeBlocks - Ninja" \
-B.' -B.'
print(f"CMake configure:\n{cmake_configure_command}\n\n")
run(cmake_configure_command, cwd=build_config.build_folder)
print(f"\nCMake build:\n")
run("cmake --build . --target all", cwd=build_config.build_folder)
# Build build_result.binary = Path(build_config.bin_dir)
start_time = time.time()
print(cmake_configure_command)
run(cmake_configure_command, cwd=build_folder)
run("cmake --build . --target all", cwd=build_folder)
bin_dir = build_folder.joinpath("bin") return build_result
# Deploy dependencies
if deploy_command: # Only deploy if we have the dependencies def deploy(build_config: BuildConfig):
if build_config.deploy_command: # Only deploy if we have the dependencies
print("Executing deploy commands...") print("Executing deploy commands...")
run(deploy_command.format( run(build_config.deploy_command.format(
type=build_type, type=build_config.build_type,
prefix_path=qt_bin_path, prefix_path=build_config.qt_bin_path,
app="ScreenPlay", app="ScreenPlay",
executable_file_ending=executable_file_ending), cwd=bin_dir) executable_file_ending=build_config.executable_file_ending), cwd=build_config.bin_dir)
run(deploy_command.format( run(build_config.deploy_command.format(
type=build_type, type=build_config.build_type,
prefix_path=qt_bin_path, prefix_path=build_config.qt_bin_path,
app="ScreenPlayWidget", app="ScreenPlayWidget",
executable_file_ending=executable_file_ending), cwd=bin_dir) executable_file_ending=build_config.executable_file_ending), cwd=build_config.bin_dir)
run(deploy_command.format( run(build_config.deploy_command.format(
type=build_type, type=build_config.build_type,
prefix_path=qt_bin_path, prefix_path=build_config.qt_bin_path,
app="ScreenPlayWallpaper", app="ScreenPlayWallpaper",
executable_file_ending=executable_file_ending), cwd=bin_dir) executable_file_ending=build_config.executable_file_ending), cwd=build_config.bin_dir)
else: else:
# just copy the folders and be done with it # just copy the folders and be done with it
if platform.system() == "Linux": if platform.system() == "Linux":
# Copy all .so files from the qt_bin_path lib folder into bin_dir # Copy all .so files from the qt_bin_path lib folder into bin_dir
qt_lib_path = qt_bin_path qt_lib_path = build_config.qt_bin_path
for file in qt_lib_path.joinpath("lib").glob("*.so"): for file in qt_lib_path.joinpath("lib").glob("*.so"):
shutil.copy(str(file), str(bin_dir)) shutil.copy(str(file), str(build_config.bin_dir))
# Copy qt_qml_path folder content into bin_dir # Copy qt_qml_path folder content into bin_dir
qt_qml_path = qt_bin_path qt_qml_path = build_config.qt_bin_path
for folder in qt_qml_path.joinpath("qml").iterdir(): for folder in qt_qml_path.joinpath("qml").iterdir():
if not folder.is_file(): if not folder.is_file():
shutil.copytree(str(folder), str( shutil.copytree(str(folder), str(
bin_dir.joinpath(folder.name))) build_config.bin_dir.joinpath(folder.name)))
print("Copied %s" % folder) print("Copied %s" % folder)
# Copy all plugin folder from qt_bin_path plugins subfolder into bin_dir # Copy all plugin folder from qt_bin_path plugins subfolder into bin_dir
qt_plugins_path = qt_bin_path qt_plugins_path = build_config.qt_bin_path
for folder in qt_bin_path.joinpath("plugins").iterdir(): for folder in build_config.qt_bin_path.joinpath("plugins").iterdir():
if not folder.is_file(): if not folder.is_file():
shutil.copytree(str(folder), str( shutil.copytree(str(folder), str(
bin_dir.joinpath(folder.name))) build_config.bin_dir.joinpath(folder.name)))
print("Copied %s" % folder) print("Copied %s" % folder)
# Copy all folder from qt_bin_path translation files into bin_dir translation folder # Copy all folder from qt_bin_path translation files into bin_dir translation folder
qt_translations_path = qt_bin_path qt_translations_path = build_config.qt_bin_path
for folder in qt_translations_path.joinpath("translations").iterdir(): for folder in qt_translations_path.joinpath("translations").iterdir():
if not folder.is_file(): if not folder.is_file():
shutil.copytree(str(folder), str( shutil.copytree(str(folder), str(
bin_dir.joinpath("translations").joinpath(folder.name))) build_config.bin_dir.joinpath("translations").joinpath(folder.name)))
print("Copied %s" % folder) print("Copied %s" % folder)
# Copy all filesfrom qt_bin_path resources folder into bin_dir folder # Copy all filesfrom qt_bin_path resources folder into bin_dir folder
qt_resources_path = qt_bin_path qt_resources_path = build_config.qt_bin_path
for file in qt_bin_path.joinpath("resources").glob("*"): for file in build_config.qt_bin_path.joinpath("resources").glob("*"):
shutil.copy(str(file), str(bin_dir)) shutil.copy(str(file), str(build_config.bin_dir))
print("Copied %s" % file) print("Copied %s" % file)
else: else:
print("Not executing deploy commands due to missing dependencies.") print("Not executing deploy commands due to missing dependencies.")
# Post-build # Copy qml dir into all .app/Contents/MacOS/
if platform.system() == "Darwin" and sign_build == "ON":
run("codesign --deep -f -s \"Developer ID Application: Elias Steurer (V887LHYKRH)\" --timestamp --options \"runtime\" -f --entitlements \"../../ScreenPlay/entitlements.plist\" --deep \"ScreenPlay.app/\"", cwd=bin_dir)
run("codesign --deep -f -s \"Developer ID Application: Elias Steurer (V887LHYKRH)\" --timestamp --options \"runtime\" -f --deep \"ScreenPlayWallpaper.app/\"", cwd=bin_dir)
run("codesign --deep -f -s \"Developer ID Application: Elias Steurer (V887LHYKRH)\" --timestamp --options \"runtime\" -f --deep \"ScreenPlayWidget.app/\"", cwd=bin_dir)
run("codesign --verify --verbose=4 \"ScreenPlay.app/\"", cwd=bin_dir)
run("codesign --verify --verbose=4 \"ScreenPlayWallpaper.app/\"", cwd=bin_dir)
run("codesign --verify --verbose=4 \"ScreenPlayWidget.app/\"", cwd=bin_dir)
run("xcnotary notarize ScreenPlay.app -d kelteseth@gmail.com -k ScreenPlay", cwd=bin_dir),
run("xcnotary notarize ScreenPlayWallpaper.app -d kelteseth@gmail.com -k ScreenPlay", cwd=bin_dir),
run("xcnotary notarize ScreenPlayWidget.app -d kelteseth@gmail.com -k ScreenPlay", cwd=bin_dir)
run("spctl --assess --verbose \"ScreenPlay.app/\"", cwd=bin_dir)
run("spctl --assess --verbose \"ScreenPlayWallpaper.app/\"", cwd=bin_dir)
run("spctl --assess --verbose \"ScreenPlayWidget.app/\"", cwd=bin_dir)
# Copy qml dir into all .app/Contents/MacOS/
if platform.system() == "Darwin": if platform.system() == "Darwin":
copytree(Path.joinpath(bin_dir, "qml"), Path.joinpath(bin_dir, "ScreenPlay.app/Contents/MacOS/qml")) copytree(Path.joinpath(build_config.bin_dir, "qml"), Path.joinpath(
copytree(Path.joinpath(bin_dir, "qml"), Path.joinpath(bin_dir, "ScreenPlayWallpaper.app/Contents/MacOS/qml")) build_config.bin_dir, "ScreenPlay.app/Contents/MacOS/qml"))
copytree(Path.joinpath(bin_dir, "qml"), Path.joinpath(bin_dir, "ScreenPlayWidget.app/Contents/MacOS/qml")) copytree(Path.joinpath(build_config.bin_dir, "qml"), Path.joinpath(
build_config.bin_dir, "ScreenPlayWallpaper.app/Contents/MacOS/qml"))
copytree(Path.joinpath(build_config.bin_dir, "qml"), Path.joinpath(
build_config.bin_dir, "ScreenPlayWidget.app/Contents/MacOS/qml"))
# 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":
vcpkg_bin_path = Path( vcpkg_bin_path = Path(
f"{root_path}/../ScreenPlay-vcpkg/installed/x64-windows/bin").resolve() f"{build_config.root_path}/../ScreenPlay-vcpkg/installed/x64-windows/bin").resolve()
print(vcpkg_bin_path) print(f"Copy dlls from vcpkg bin path: {vcpkg_bin_path}")
for file in vcpkg_bin_path.iterdir(): for file in vcpkg_bin_path.iterdir():
if file.suffix == ".dll" and file.is_file(): if file.suffix == ".dll" and file.is_file():
print(file, bin_dir) print(file, build_config.bin_dir)
shutil.copy2(file, bin_dir) shutil.copy2(file, build_config.bin_dir)
if not platform.system() == "Darwin": if not platform.system() == "Darwin":
file_endings = [".ninja_deps", ".ninja", ".ninja_log", ".lib", ".a", ".exp",
".manifest", ".cmake", ".cbp", "CMakeCache.txt"]
for file_ending in file_endings: for file_ending in file_endings:
for file in bin_dir.rglob("*" + file_ending): for file in build_config.bin_dir.rglob("*" + file_ending):
if file.is_file(): if file.is_file():
print("Remove: %s" % file.resolve()) print("Remove: %s" % file.resolve())
file.unlink() file.unlink()
if create_installer == "ON":
os.chdir(build_folder)
print("Running cpack at: ", os.getcwd())
run("cpack", cwd=build_folder)
# We also need to sign the installer in osx:
if platform.system() == "Darwin" and sign_build == "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_folder)
run("codesign --verify --verbose=4 \"ScreenPlay-Installer.dmg/ScreenPlay-Installer.app/Contents/MacOS/ScreenPlay-Installer\"", cwd=build_folder)
run("xcnotary notarize ScreenPlay-Installer.dmg/ScreenPlay-Installer.app -d kelteseth@gmail.com -k ScreenPlay", cwd=build_folder)
run("spctl --assess --verbose \"ScreenPlay-Installer.dmg/ScreenPlay-Installer.app/\"", cwd=build_folder)
run("codesign --deep -f -s \"Developer ID Application: Elias Steurer (V887LHYKRH)\" --timestamp --options \"runtime\" -f --deep \"ScreenPlay-Installer.dmg/\"", cwd=build_folder) def create_installer(build_config: BuildConfig, build_result: BuildResult):
run("codesign --verify --verbose=4 \"ScreenPlay-Installer.dmg/\"", os.chdir(build_result.build)
cwd=build_folder) print("Running cpack at: ", os.getcwd())
run("xcnotary notarize ScreenPlay-Installer.dmg -d kelteseth@gmail.com -k ScreenPlay", cwd=build_folder) run("cpack", cwd=build_config.build_folder)
run("spctl --assess --verbose \"ScreenPlay-Installer.dmg/\"",
cwd=build_folder)
# Create a zip file for scoop
if platform.system() == "Windows":
zipName = f"ScreenPlay-{SCREENPLAY_VERSION}-{cmake_target_triplet}-{build_type}.zip"
print(f"Creating scoop zip file: \n{bin_dir} \n{zipName}")
os.chdir(build_folder)
with zipfile.ZipFile(zipName, 'w', zipfile.ZIP_DEFLATED) as zipf:
zipdir(bin_dir, zipf)
print("Time taken: {}s".format(time.time() - start_time)) def sign(build_config: BuildConfig):
run("codesign --deep -f -s \"Developer ID Application: Elias Steurer (V887LHYKRH)\" --timestamp --options \"runtime\" -f --entitlements \"../../ScreenPlay/entitlements.plist\" --deep \"ScreenPlay.app/\"", cwd=build_config.bin_dir)
run("codesign --deep -f -s \"Developer ID Application: Elias Steurer (V887LHYKRH)\" --timestamp --options \"runtime\" -f --deep \"ScreenPlayWallpaper.app/\"", cwd=build_config.bin_dir)
run("codesign --deep -f -s \"Developer ID Application: Elias Steurer (V887LHYKRH)\" --timestamp --options \"runtime\" -f --deep \"ScreenPlayWidget.app/\"", cwd=build_config.bin_dir)
run("codesign --verify --verbose=4 \"ScreenPlay.app/\"", cwd=build_config.bin_dir)
run("codesign --verify --verbose=4 \"ScreenPlayWallpaper.app/\"",
cwd=build_config.bin_dir)
run("codesign --verify --verbose=4 \"ScreenPlayWidget.app/\"",
cwd=build_config.bin_dir)
run("xcnotary notarize ScreenPlay.app -d kelteseth@gmail.com -k ScreenPlay",
cwd=build_config.bin_dir),
run("xcnotary notarize ScreenPlayWallpaper.app -d kelteseth@gmail.com -k ScreenPlay",
cwd=build_config.bin_dir),
run("xcnotary notarize ScreenPlayWidget.app -d kelteseth@gmail.com -k ScreenPlay",
cwd=build_config.bin_dir)
run("spctl --assess --verbose \"ScreenPlay.app/\"", cwd=build_config.bin_dir)
run("spctl --assess --verbose \"ScreenPlayWallpaper.app/\"",
cwd=build_config.bin_dir)
run("spctl --assess --verbose \"ScreenPlayWidget.app/\"",
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 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_config.bin_dir).joinpath(zipName)
print(f"Creating scoop zip file")
os.chdir(build_config.build_folder)
with zipfile.ZipFile(zipName, 'w', zipfile.ZIP_DEFLATED) as zipf:
zipdir(build_config.bin_dir, zipf)
# Create sha256 hash from zip file
zip_file_path = os.path.join(build_result.build, zipName)
build_hash = sha256(zip_file_path)
build_result.build_hash = Path(
build_result.build).joinpath(zipName + ".sha256.txt")
f = open(build_result.build_hash, "a")
f.write(build_hash)
f.close()
# Some weird company firewalls do not allow direct .exe downloads
# lets just zip the installer lol
installer_zip = build_result.installer.stem + ".zip"
build_result.installer_zip = Path(build_result.build).joinpath(build_result.installer.stem + ".zip")
zipfile.ZipFile(installer_zip, mode='w').write(build_result.installer)
return build_result
if __name__ == "__main__": if __name__ == "__main__":
@ -381,7 +483,7 @@ if __name__ == "__main__":
qt_version = "6.3.1" qt_version = "6.3.1"
qt_ifw_version = "4.4" # Not yet used. qt_ifw_version = "4.4" # Not yet used.
qt_version_overwrite = "" qt_version_overwrite: str
use_aqt = False use_aqt = False
if args.qt_version_overwrite: if args.qt_version_overwrite:
@ -393,7 +495,7 @@ if __name__ == "__main__":
print("Using Qt installer framework version {qt_ifw_version}") print("Using Qt installer framework version {qt_ifw_version}")
if not args.build_type: if not args.build_type:
print("Build type argument is missing (release, debug). E.g: python build.py -type release -steam") print("Build type argument is missing (release, debug). E.g: python build_config.py -type release -steam")
print( print(
f"Defaulting to Qt version: {qt_version}. This can be overwritten via -qt-version 6.5.0") f"Defaulting to Qt version: {qt_version}. This can be overwritten via -qt-version 6.5.0")
exit(1) exit(1)
@ -415,19 +517,20 @@ if __name__ == "__main__":
if args.create_installer: if args.create_installer:
create_installer = "ON" create_installer = "ON"
sign_build = "OFF" sign_build = False
if args.sign_build: if args.sign_build:
sign_build = "ON" sign_build = True
build( build_config = BuildConfig()
qt_version, build_config.qt_version = qt_version
qt_ifw_version, build_config.qt_ifw_version = qt_ifw_version
build_steam, build_config.build_steam = build_steam
build_tests, build_config.build_tests = build_tests
build_release, build_config.build_release = build_release
create_installer, build_config.create_installer = create_installer
build_type, build_config.build_type = build_type
sign_build, build_config.sign_build = args.sign_build
args.use_aqt, build_config.use_aqt = use_aqt
args.build_architecture build_config.build_architecture = args.build_architecture
)
execute(build_config)

View File

@ -1,14 +1,17 @@
from build import build
import steam_publish import steam_publish
import argparse import argparse
import os import os
import build
from pathlib import Path from pathlib import Path
from macos_lipo import run_lipo, check_fat_binary from macos_lipo import run_lipo, check_fat_binary
import platform import platform
import ftplib
if __name__ == "__main__": if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Build and Package ScreenPlay') parser = argparse.ArgumentParser(description='Build and Package ScreenPlay')
parser.add_argument('-steam_password', action="store", dest="steam_password", required=True, help="Steam password") parser.add_argument('-steam_password', action="store", dest="steam_password", required=True, help="Steam password")
parser.add_argument('-hosting_password', action="store", dest="hosting_password", required=True, help="FTPS 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
@ -17,54 +20,52 @@ 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}")
build_result = build.BuildResult()
build_config = build.BuildConfig()
build_config.screenplay_version = "0.15.0-RC1"
build_config.qt_version = "6.3.1"
build_config.qt_ifw_version = "4.4"
build_config.build_steam = "ON"
build_config.build_tests = "OFF"
build_config.build_release = "ON"
build_config.create_installer = "ON"
build_config.build_type = "release"
build_config.sign_build = True
build_config.use_aqt = False
if platform.system() == "Darwin": if platform.system() == "Darwin":
# OSX builds needs to build for x86 and arm # OSX builds needs to build for x86 and arm
# and also be signed! # and also be signed!
build(
qt_version="6.4.0", build_config.build_architecture = "arm64"
qt_ifw_version="4.4", build_result = build.execute(build_config)
build_steam="ON",
build_tests="OFF", build_config.build_architecture = "x64"
build_release="ON", build_result = build.execute(build_config)
create_installer="ON",
build_type="release",
sign_build=True,
use_aqt=False,
build_architecture = "arm64"
)
build(
qt_version="6.4.0",
qt_ifw_version="4.4",
build_steam="ON",
build_tests="OFF",
build_release="ON",
create_installer="OFF",
build_type="release",
sign_build=True,
use_aqt=False,
build_architecture = "x64"
)
# Make sure to reset to tools path # Make sure to reset to tools path
os.chdir(root_path) os.chdir(root_path)
# Create universal (fat) binary # Create universal (fat) binary
run_lipo() run_lipo()
check_fat_binary() check_fat_binary()
else: else:
build(
qt_version="6.4.0", build_config.build_architecture = "x64"
qt_ifw_version="4.4", build_result = build.execute(build_config)
build_steam="ON",
build_tests="OFF",
build_release="ON",
create_installer="OFF",
build_type="release",
sign_build=False,
use_aqt=False
)
# Make sure to reset to tools path # Make sure to reset to tools path
os.chdir(tools_path) #os.chdir(tools_path)
#steam_publish( #steam_publish.publish(
# steam_username="tachiom", # steam_username="tachiom",
# steam_password=args.steam_password, # steam_password=args.steam_password,
# set_live_branch_name="internal" # set_live_branch_name="internal"
#) #)
#session = ftplib.FTP('wallpaper.software','screenplay_releases',args.hosting_password)
#file = open('kitten.jpg','rb') # file to send
#session.storbinary('STOR kitten.jpg', file) # send the file
#file.close() # close file and FTP
#session.quit()

View File

@ -21,7 +21,7 @@ def get_git_revision_short_hash():
def get_git_commit_text(): def get_git_commit_text():
return subprocess.check_output(['git', 'log', '-1', '--pretty=%B']) return subprocess.check_output(['git', 'log', '-1', '--pretty=%B'])
def steam_publish( def publish(
steam_username, steam_username,
steam_password, steam_password,
set_live_branch_name set_live_branch_name
@ -102,7 +102,7 @@ if __name__ == "__main__":
else: else:
set_live_branch_name = "internal" set_live_branch_name = "internal"
steam_publish( publish(
steam_username=args.steam_username, steam_username=args.steam_username,
steam_password=args.steam_password, steam_password=args.steam_password,
set_live_branch_name=set_live_branch_name set_live_branch_name=set_live_branch_name

View File

@ -1,17 +1,17 @@
import hashlib
from pathlib import Path from pathlib import Path
from pathlib import Path from pathlib import Path
from os import chdir from os import chdir
from concurrent.futures import ThreadPoolExecutor
import os
import subprocess import subprocess
import zipfile
def run(cmd, cwd=Path.cwd()): def run(cmd, cwd=Path.cwd()):
result = subprocess.run(cmd, shell=True, cwd=cwd) result = subprocess.run(cmd, shell=True, cwd=cwd)
if result.returncode != 0: if result.returncode != 0:
raise RuntimeError(f"Failed to execute {cmd}") raise RuntimeError(f"Failed to execute {cmd}")
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
@ -21,3 +21,27 @@ def cd_repo_root_path() -> str:
print(f"Change root directory to: {root_path}") print(f"Change root directory to: {root_path}")
chdir(root_path) chdir(root_path)
return root_path return root_path
def sha256(fname) -> str:
hash_sha256 = hashlib.sha256()
with open(fname, "rb") as f:
for chunk in iter(lambda: f.read(4096), b""):
hash_sha256.update(chunk)
return hash_sha256.hexdigest()
def zipdir(path, ziph):
# ziph is zipfile handle
for root, dirs, files in os.walk(path):
for file in files:
ziph.write(os.path.join(root, file),
os.path.relpath(os.path.join(root, file),
os.path.join(path, '..')))
def run_io_tasks_in_parallel(tasks):
with ThreadPoolExecutor() as executor:
running_tasks = [executor.submit(task) for task in tasks]
for running_task in running_tasks:
running_task.result()