mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-14 19:29:36 +01:00
271 lines
7.9 KiB
Python
271 lines
7.9 KiB
Python
#!/usr/bin/env python3
|
|
# Packages a full release build of the client that can be loaded by the launcher.
|
|
# Native libraries are not included.
|
|
|
|
import os
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import zipfile
|
|
import argparse
|
|
import glob
|
|
|
|
from typing import List, Optional
|
|
|
|
try:
|
|
from colorama import init, Fore, Style
|
|
init()
|
|
|
|
except ImportError:
|
|
# Just give an empty string for everything, no colored logging.
|
|
class ColorDummy(object):
|
|
def __getattr__(self, name):
|
|
return ""
|
|
|
|
Fore = ColorDummy()
|
|
Style = ColorDummy()
|
|
|
|
|
|
p = os.path.join
|
|
|
|
PLATFORM_WINDOWS = "win-x64"
|
|
PLATFORM_LINUX = "linux-x64"
|
|
PLATFORM_LINUX_ARM64 = "linux-arm64"
|
|
PLATFORM_MACOS = "osx-x64"
|
|
|
|
TARGET_FRAMEWORK = "net10.0"
|
|
|
|
def main() -> None:
|
|
parser = argparse.ArgumentParser(
|
|
description="Packages the Robust.Client.WebView module for release on all platforms.")
|
|
parser.add_argument("--platform",
|
|
"-p",
|
|
action="store",
|
|
choices=[PLATFORM_WINDOWS, PLATFORM_MACOS, PLATFORM_LINUX, PLATFORM_LINUX_ARM64],
|
|
nargs="*",
|
|
help="Which platform to build for. If not provided, all platforms will be built")
|
|
|
|
parser.add_argument("--skip-build",
|
|
action="store_true",
|
|
help=argparse.SUPPRESS)
|
|
|
|
args = parser.parse_args()
|
|
platforms = args.platform
|
|
skip_build = args.skip_build
|
|
|
|
if not platforms:
|
|
platforms = [PLATFORM_WINDOWS, PLATFORM_LINUX]
|
|
|
|
if os.path.exists("release"):
|
|
print(Fore.BLUE + Style.DIM +
|
|
"Cleaning old release packages (release/Robust.Client.WebView_*)..." + Style.RESET_ALL)
|
|
for past in glob.glob("release/Robust.Client.WebView_*"):
|
|
os.remove(past)
|
|
else:
|
|
os.mkdir("release")
|
|
|
|
if PLATFORM_WINDOWS in platforms:
|
|
if not skip_build:
|
|
wipe_bin()
|
|
build_windows(skip_build)
|
|
|
|
if PLATFORM_LINUX in platforms:
|
|
if not skip_build:
|
|
wipe_bin()
|
|
build_linux(skip_build)
|
|
|
|
def wipe_bin():
|
|
print(Fore.BLUE + Style.DIM +
|
|
"Clearing old build artifacts (if any)..." + Style.RESET_ALL)
|
|
|
|
RCWebViewBin = p("Robust.Client.WebView", "bin")
|
|
if os.path.exists(RCWebViewBin):
|
|
shutil.rmtree(RCWebViewBin)
|
|
|
|
|
|
def build_windows(skip_build: bool) -> None:
|
|
# Run a full build.
|
|
print(Fore.GREEN + "Building project for Windows x64..." + Style.RESET_ALL)
|
|
|
|
base_bin = p("Robust.Client.WebView", "bin", "Release", TARGET_FRAMEWORK)
|
|
|
|
if not skip_build:
|
|
build_client_rid("Windows", "win-x64")
|
|
build_client("Windows")
|
|
if sys.platform != "win32":
|
|
subprocess.run(["Tools/exe_set_subsystem.py", p(base_bin, "Robust.Client.WebView.exe"), "2"])
|
|
|
|
|
|
print(Fore.GREEN + "Packaging win-x64..." + Style.RESET_ALL)
|
|
|
|
client_zip = zipfile.ZipFile(
|
|
p("release", "Robust.Client.WebView_win-x64.zip"), "w",
|
|
compression=zipfile.ZIP_DEFLATED)
|
|
|
|
files_to_copy = [
|
|
"Robust.Client.WebView.dll",
|
|
"Robust.Client.WebView.exe",
|
|
"Robust.Client.WebView.runtimeconfig.json",
|
|
"Robust.Client.WebView.pdb",
|
|
"Robust.Client.WebView.deps.json",
|
|
"SpaceWizards.CefGlue.dll",
|
|
"SpaceWizards.CefGlue.pdb",
|
|
# These are copies of regular Robust dlls that Robust.Client.WebView needs when ran on its own.
|
|
"Robust.Client.dll",
|
|
"Robust.Shared.dll",
|
|
"Robust.Shared.Maths.dll",
|
|
"SharpZstd.Interop.dll",
|
|
]
|
|
|
|
for f in files_to_copy:
|
|
client_zip.write(p(base_bin, "win-x64", f), f)
|
|
|
|
copy_dir_into_zip(p(base_bin, "runtimes", "win-x64", "native"), "", client_zip, {
|
|
"e_sqlite3.dll",
|
|
"fluidsynth.dll",
|
|
"freetype6.dll",
|
|
"glfw3.dll",
|
|
"libglib-2.0-0.dll",
|
|
"libgobject-2.0-0.dll",
|
|
"libgthread-2.0-0.dll",
|
|
"libinstpatch-2.dll",
|
|
"libintl-8.dll",
|
|
"libsndfile-1.dll",
|
|
"openal32.dll",
|
|
"swnfd.dll",
|
|
"zstd.pdb",
|
|
"zstd.dll",
|
|
"zlib1.dll",
|
|
"libsodium.dll"
|
|
})
|
|
|
|
# Cool we're done.
|
|
client_zip.close()
|
|
|
|
def build_linux(skip_build: bool) -> None:
|
|
# Run a full build.
|
|
print(Fore.GREEN + "Building project for Linux x64..." + Style.RESET_ALL)
|
|
|
|
base_bin = p("Robust.Client.WebView", "bin", "Release", TARGET_FRAMEWORK)
|
|
|
|
if not skip_build:
|
|
build_client_rid("Linux", "linux-x64")
|
|
build_client("Linux")
|
|
|
|
print(Fore.GREEN + "Packaging linux-x64..." + Style.RESET_ALL)
|
|
|
|
client_zip = zipfile.ZipFile(
|
|
p("release", "Robust.Client.WebView_linux-x64.zip"), "w",
|
|
compression=zipfile.ZIP_DEFLATED)
|
|
|
|
files_to_copy = [
|
|
"Robust.Client.WebView.dll",
|
|
"Robust.Client.WebView.runtimeconfig.json",
|
|
"Robust.Client.WebView.pdb",
|
|
"Robust.Client.WebView",
|
|
"Robust.Client.WebView.deps.json",
|
|
"SpaceWizards.CefGlue.dll",
|
|
"SpaceWizards.CefGlue.pdb",
|
|
# These are copies of regular Robust dlls that Robust.Client.WebView needs when ran on its own.
|
|
"Robust.Client.dll",
|
|
"Robust.Shared.dll",
|
|
"Robust.Shared.Maths.dll",
|
|
"SharpZstd.Interop.dll",
|
|
]
|
|
|
|
for f in files_to_copy:
|
|
client_zip.write(p(base_bin, "linux-x64", f), f)
|
|
|
|
copy_dir_into_zip(p(base_bin, "runtimes", "linux-x64", "native"), "", client_zip, {
|
|
"libglfw.so.3",
|
|
"libe_sqlite3.so",
|
|
"libopenal.so",
|
|
"libswnfd.so",
|
|
})
|
|
|
|
# Cool we're done.
|
|
client_zip.close()
|
|
|
|
|
|
def build_client(target_os: str) -> None:
|
|
# Running a publish will fold all the natives in the runtime directories into one folder.
|
|
# This basically nukes the entire setup.
|
|
# As bypass, we do an all-platform build and then copy the natives manually.
|
|
base = [
|
|
"dotnet", "build",
|
|
"-c", "Release",
|
|
f"/p:TargetOS={target_os}",
|
|
"/p:FullRelease=True",
|
|
"--no-self-contained",
|
|
]
|
|
|
|
subprocess.run(base + ["Robust.Client.WebView/Robust.Client.WebView.csproj"], check=True)
|
|
|
|
def build_client_rid(target_os: str, rid: str) -> None:
|
|
base = [
|
|
"dotnet", "build",
|
|
"-c", "Release",
|
|
"-r", rid,
|
|
f"/p:TargetOS={target_os}",
|
|
"/p:FullRelease=True",
|
|
"--no-self-contained",
|
|
]
|
|
|
|
subprocess.run(base + ["Robust.Client.WebView/Robust.Client.WebView.csproj"], check=True)
|
|
|
|
|
|
def zip_entry_exists(zipf, name):
|
|
try:
|
|
# Trick ZipInfo into sanitizing the name for us so this awful module stops spewing warnings.
|
|
zinfo = zipfile.ZipInfo.from_file("Resources", name)
|
|
zipf.getinfo(zinfo.filename)
|
|
except KeyError:
|
|
return False
|
|
return True
|
|
|
|
|
|
def copy_dir_into_zip(directory, basepath, zipf, ignored={}):
|
|
if basepath and not zip_entry_exists(zipf, basepath):
|
|
zipf.write(directory, basepath)
|
|
|
|
for root, _, files in os.walk(directory):
|
|
relpath = os.path.relpath(root, directory)
|
|
if relpath != "." and not zip_entry_exists(zipf, p(basepath, relpath)):
|
|
zipf.write(root, p(basepath, relpath))
|
|
|
|
for filename in files:
|
|
zippath = p(basepath, relpath, filename)
|
|
filepath = p(root, filename)
|
|
|
|
if filename in ignored:
|
|
continue
|
|
|
|
message = "{dim}{diskroot}{sep}{zipfile}{dim} -> {ziproot}{sep}{zipfile}".format(
|
|
sep=os.sep + Style.NORMAL,
|
|
dim=Style.DIM,
|
|
diskroot=directory,
|
|
ziproot=zipf.filename,
|
|
zipfile=os.path.normpath(zippath))
|
|
|
|
print(Fore.CYAN + message + Style.RESET_ALL)
|
|
zipf.write(filepath, zippath)
|
|
|
|
|
|
def copy_dir_or_file(src: str, dst: str):
|
|
"""
|
|
Just something from src to dst. If src is a dir it gets copied recursively.
|
|
"""
|
|
|
|
if os.path.isfile(src):
|
|
shutil.copy2(src, dst)
|
|
|
|
elif os.path.isdir(src):
|
|
shutil.copytree(src, dst)
|
|
|
|
else:
|
|
raise IOError("{} is neither file nor directory. Can't copy.".format(src))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|