Files
crystall-punk-14/Tools/package_release_build.py

425 lines
13 KiB
Python
Raw Normal View History

2017-08-06 23:15:39 +02:00
#!/usr/bin/env python3
2017-08-09 13:43:14 +02:00
# Packages a full release build that can be unzipped and you'll have your SS14 client or server.
2017-08-06 23:15:39 +02:00
import os
import shutil
import subprocess
2017-08-14 15:05:39 +02:00
import sys
2017-08-06 23:15:39 +02:00
import zipfile
2017-08-14 15:05:39 +02:00
import argparse
2017-08-06 23:15:39 +02:00
2019-12-16 00:46:09 +01:00
from typing import List, Optional
2017-08-06 23:15:39 +02:00
try:
2017-08-14 15:05:39 +02:00
from colorama import init, Fore, Style
2017-08-06 23:15:39 +02:00
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()
2019-12-16 00:46:09 +01:00
p = os.path.join
2019-12-16 00:46:09 +01:00
PLATFORM_WINDOWS = "windows"
PLATFORM_LINUX = "linux"
2020-04-27 11:32:05 +02:00
PLATFORM_LINUX_ARM64 = "linux-arm64"
2019-12-16 00:46:09 +01:00
PLATFORM_MACOS = "mac"
SHARED_IGNORED_RESOURCES = {
"ss13model.7z",
"ResourcePack.zip",
"buildResourcePack.py",
2019-03-21 21:19:18 +01:00
"CONTENT_GOES_HERE",
".gitignore",
".directory",
".DS_Store"
}
CLIENT_IGNORED_RESOURCES = {
"Maps",
2019-03-21 21:19:18 +01:00
"emotes.xml",
"Groups"
}
SERVER_IGNORED_RESOURCES = {
"Textures",
2019-03-21 21:19:18 +01:00
"Fonts",
"Audio",
"Scenes",
"Nano",
"Shaders",
}
2019-07-30 01:08:36 +02:00
LAUNCHER_RESOURCES = {
"Nano",
"Fonts",
}
2019-12-16 00:46:09 +01:00
WINDOWS_NATIVES = {
"freetype6.dll",
"openal32.dll",
"swnfd.dll",
2020-05-01 20:45:49 +02:00
"glfw3.dll",
"fluidsynth.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"
2019-12-16 00:46:09 +01:00
}
LINUX_NATIVES = {
"libglfw.so.3",
"libswnfd.so"
}
MAC_NATIVES = {
"libglfw.3.dylib",
"libswnfd.dylib"
}
SERVER_EXTRA_CONTENT_ASSEMBLIES = [
"Content.Server.Database.dll"
]
2019-12-16 00:46:09 +01:00
def main() -> None:
2017-08-14 15:05:39 +02:00
parser = argparse.ArgumentParser(
description="Packages the SS14 content repo for release on all platforms.")
parser.add_argument("--platform",
"-p",
2017-08-14 15:05:39 +02:00
action="store",
2020-04-27 11:32:05 +02:00
choices=[PLATFORM_WINDOWS, PLATFORM_MACOS, PLATFORM_LINUX, PLATFORM_LINUX_ARM64],
2017-10-21 15:32:22 +02:00
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)
2017-08-14 15:05:39 +02:00
args = parser.parse_args()
2017-10-21 15:32:22 +02:00
platforms = args.platform
skip_build = args.skip_build
2017-10-21 15:32:22 +02:00
if not platforms:
2019-12-16 00:46:09 +01:00
platforms = [PLATFORM_WINDOWS, PLATFORM_MACOS, PLATFORM_LINUX]
2017-08-06 23:15:39 +02:00
2017-08-09 13:43:14 +02:00
if os.path.exists("release"):
print(Fore.BLUE + Style.DIM +
"Cleaning old release packages (release/)..." + Style.RESET_ALL)
2017-08-09 13:43:14 +02:00
shutil.rmtree("release")
2017-08-14 15:05:39 +02:00
2017-08-09 13:43:14 +02:00
os.mkdir("release")
2019-12-16 00:46:09 +01:00
if PLATFORM_WINDOWS in platforms:
if not skip_build:
wipe_bin()
build_windows(skip_build)
2017-08-14 15:05:39 +02:00
2019-12-16 00:46:09 +01:00
if PLATFORM_LINUX in platforms:
if not skip_build:
wipe_bin()
build_linux(skip_build)
2017-08-14 15:05:39 +02:00
2020-04-27 11:32:05 +02:00
if PLATFORM_LINUX_ARM64 in platforms:
if not skip_build:
wipe_bin()
build_linux_arm64(skip_build)
2019-12-16 00:46:09 +01:00
if PLATFORM_MACOS in platforms:
if not skip_build:
wipe_bin()
build_macos(skip_build)
2017-08-06 23:15:39 +02:00
2017-08-14 15:05:39 +02:00
def wipe_bin():
print(Fore.BLUE + Style.DIM +
"Clearing old build artifacts (if any)..." + Style.RESET_ALL)
if os.path.exists(p("RobustToolbox", "bin")):
shutil.rmtree(p("RobustToolbox", "bin"))
2017-08-09 11:13:04 +02:00
if os.path.exists("bin"):
shutil.rmtree("bin")
def build_windows(skip_build: bool) -> None:
2017-08-06 23:15:39 +02:00
# Run a full build.
2019-03-21 21:19:18 +01:00
print(Fore.GREEN + "Building project for Windows x64..." + Style.RESET_ALL)
2019-12-16 00:46:09 +01:00
if not skip_build:
subprocess.run([
"dotnet",
"build",
"SpaceStation14.sln",
"-c", "Release",
"--nologo",
"/v:m",
"/p:TargetOS=Windows",
"/t:Rebuild",
"/p:FullRelease=True"
], check=True)
publish_client_server("win-x64", "Windows")
2017-08-06 23:15:39 +02:00
2019-03-21 21:19:18 +01:00
print(Fore.GREEN + "Packaging Windows x64 client..." + Style.RESET_ALL)
2017-08-06 23:15:39 +02:00
2019-03-21 21:19:18 +01:00
client_zip = zipfile.ZipFile(
p("release", "SS14.Client_Windows_x64.zip"), "w",
compression=zipfile.ZIP_DEFLATED)
2019-12-16 00:46:09 +01:00
copy_dir_into_zip(p("RobustToolbox", "bin", "Client", "win-x64", "publish"), "", client_zip)
copy_client_natives(WINDOWS_NATIVES, client_zip, "")
2019-03-21 21:19:18 +01:00
copy_resources("Resources", client_zip, server=False)
copy_content_assemblies(p("Resources", "Assemblies"), client_zip, server=False)
2018-05-13 14:37:09 +02:00
# Cool we're done.
client_zip.close()
2019-03-21 21:19:18 +01:00
print(Fore.GREEN + "Packaging Windows x64 server..." + Style.RESET_ALL)
server_zip = zipfile.ZipFile(p("release", "SS14.Server_Windows_x64.zip"), "w",
2018-05-13 14:37:09 +02:00
compression=zipfile.ZIP_DEFLATED)
2019-12-16 00:46:09 +01:00
copy_dir_into_zip(p("RobustToolbox", "bin", "Server", "win-x64", "publish"), "", server_zip)
copy_resources(p("Resources"), server_zip, server=True)
2019-03-21 21:19:18 +01:00
copy_content_assemblies(p("Resources", "Assemblies"), server_zip, server=True)
server_zip.close()
2017-08-14 15:05:39 +02:00
def build_macos(skip_build: bool) -> None:
2019-03-21 21:19:18 +01:00
print(Fore.GREEN + "Building project for macOS x64..." + Style.RESET_ALL)
2019-12-16 00:46:09 +01:00
if not skip_build:
subprocess.run([
"dotnet",
"build",
"SpaceStation14.sln",
"-c", "Release",
"--nologo",
"/v:m",
"/p:TargetOS=MacOS",
"/t:Rebuild",
"/p:FullRelease=True"
], check=True)
publish_client_server("osx-x64", "MacOS")
2017-08-09 11:13:04 +02:00
2019-03-21 21:19:18 +01:00
print(Fore.GREEN + "Packaging macOS x64 client..." + Style.RESET_ALL)
2018-05-13 14:37:09 +02:00
# Client has to go in an app bundle.
2019-03-21 21:19:18 +01:00
client_zip = zipfile.ZipFile(p("release", "SS14.Client_macOS_x64.zip"), "a",
2018-05-13 14:37:09 +02:00
compression=zipfile.ZIP_DEFLATED)
2019-03-21 21:19:18 +01:00
contents = p("Space Station 14.app", "Contents", "Resources")
copy_dir_into_zip(p("BuildFiles", "Mac", "Space Station 14.app"), "Space Station 14.app", client_zip)
2019-12-16 00:46:09 +01:00
copy_dir_into_zip(p("RobustToolbox", "bin", "Client", "osx-x64", "publish"), contents, client_zip)
copy_client_natives(MAC_NATIVES, client_zip, contents)
2019-03-21 21:19:18 +01:00
copy_resources(p(contents, "Resources"), client_zip, server=False)
copy_content_assemblies(p(contents, "Resources", "Assemblies"), client_zip, server=False)
2018-05-13 14:37:09 +02:00
client_zip.close()
2019-03-21 21:19:18 +01:00
print(Fore.GREEN + "Packaging macOS x64 server..." + Style.RESET_ALL)
server_zip = zipfile.ZipFile(p("release", "SS14.Server_macOS_x64.zip"), "w",
2018-05-13 14:37:09 +02:00
compression=zipfile.ZIP_DEFLATED)
2019-12-16 00:46:09 +01:00
copy_dir_into_zip(p("RobustToolbox", "bin", "Server", "osx-x64", "publish"), "", server_zip)
copy_resources(p("Resources"), server_zip, server=True)
2019-03-21 21:19:18 +01:00
copy_content_assemblies(p("Resources", "Assemblies"), server_zip, server=True)
server_zip.close()
2017-08-09 11:13:04 +02:00
2019-07-30 01:08:36 +02:00
def build_linux(skip_build: bool) -> None:
2019-03-21 21:19:18 +01:00
# Run a full build.
print(Fore.GREEN + "Building project for Linux x64..." + Style.RESET_ALL)
2019-12-16 00:46:09 +01:00
if not skip_build:
subprocess.run([
"dotnet",
"build",
"SpaceStation14.sln",
"-c", "Release",
"--nologo",
"/v:m",
"/p:TargetOS=Linux",
"/t:Rebuild",
"/p:FullRelease=True"
], check=True)
publish_client_server("linux-x64", "Linux")
2017-08-14 15:05:39 +02:00
2019-03-21 21:19:18 +01:00
print(Fore.GREEN + "Packaging Linux x64 client..." + Style.RESET_ALL)
2018-06-08 15:39:48 +02:00
2019-03-21 21:19:18 +01:00
client_zip = zipfile.ZipFile(
p("release", "SS14.Client_Linux_x64.zip"), "w",
compression=zipfile.ZIP_DEFLATED)
2018-06-08 15:39:48 +02:00
2019-12-16 00:46:09 +01:00
copy_dir_into_zip(p("RobustToolbox", "bin", "Client", "linux-x64", "publish"), "", client_zip)
2019-03-21 21:19:18 +01:00
copy_resources("Resources", client_zip, server=False)
2019-12-16 00:46:09 +01:00
copy_client_natives(LINUX_NATIVES, client_zip, "")
2019-03-21 21:19:18 +01:00
copy_content_assemblies(p("Resources", "Assemblies"), client_zip, server=False)
2018-06-08 15:39:48 +02:00
# Cool we're done.
client_zip.close()
2019-03-21 21:19:18 +01:00
print(Fore.GREEN + "Packaging Linux x64 server..." + Style.RESET_ALL)
server_zip = zipfile.ZipFile(p("release", "SS14.Server_Linux_x64.zip"), "w",
2018-05-13 14:37:09 +02:00
compression=zipfile.ZIP_DEFLATED)
2019-12-16 00:46:09 +01:00
copy_dir_into_zip(p("RobustToolbox", "bin", "Server", "linux-x64", "publish"), "", server_zip)
2018-05-13 14:37:09 +02:00
copy_resources(p("Resources"), server_zip, server=True)
2019-03-21 21:19:18 +01:00
copy_content_assemblies(p("Resources", "Assemblies"), server_zip, server=True)
2018-05-13 14:37:09 +02:00
server_zip.close()
2020-04-27 11:32:05 +02:00
def build_linux_arm64(skip_build: bool) -> None:
# Run a full build.
print(Fore.GREEN + "Building project for Linux ARM64 (SERVER ONLY)..." + Style.RESET_ALL)
if not skip_build:
subprocess.run([
"dotnet",
"build",
"SpaceStation14.sln",
"-c", "Release",
"--nologo",
"/v:m",
"/p:TargetOS=Linux",
"/t:Rebuild",
"/p:FullRelease=True"
], check=True)
publish_client_server("linux-arm64", "Linux", True)
print(Fore.GREEN + "Packaging Linux ARM64 server..." + Style.RESET_ALL)
server_zip = zipfile.ZipFile(p("release", "SS14.Server_Linux_ARM64.zip"), "w",
compression=zipfile.ZIP_DEFLATED)
copy_dir_into_zip(p("RobustToolbox", "bin", "Server", "linux-arm64", "publish"), "", server_zip)
copy_resources(p("Resources"), server_zip, server=True)
copy_content_assemblies(p("Resources", "Assemblies"), server_zip, server=True)
server_zip.close()
def publish_client_server(runtime: str, target_os: str, actually_only_server: bool = False) -> None:
2019-12-16 00:46:09 +01:00
# Runs dotnet publish on client and server.
base = [
"dotnet", "publish",
"--runtime", runtime,
"--no-self-contained",
"-c", "Release",
2020-01-30 13:47:13 +01:00
f"/p:TargetOS={target_os}",
2020-06-08 23:36:12 +02:00
"/p:FullRelease=True"
2019-12-16 00:46:09 +01:00
]
2019-07-30 01:08:36 +02:00
2020-04-27 11:32:05 +02:00
if not actually_only_server:
subprocess.run(base + ["RobustToolbox/Robust.Client/Robust.Client.csproj"], check=True)
2019-12-16 00:46:09 +01:00
subprocess.run(base + ["RobustToolbox/Robust.Server/Robust.Server.csproj"], check=True)
2020-04-27 11:32:05 +02:00
def copy_resources(target, zipf, server):
# Content repo goes FIRST so that it won't override engine files as that's forbidden.
2019-07-30 01:08:36 +02:00
ignore_set = SHARED_IGNORED_RESOURCES
if server:
ignore_set = ignore_set.union(SERVER_IGNORED_RESOURCES)
else:
ignore_set = ignore_set.union(CLIENT_IGNORED_RESOURCES)
2019-07-30 01:08:36 +02:00
do_resource_copy(target, "Resources", zipf, ignore_set)
do_resource_copy(target, p("RobustToolbox", "Resources"), zipf, ignore_set)
2019-07-30 01:08:36 +02:00
def copy_launcher_resources(target, zipf):
# Copy all engine resources, since those are stripped down enough now.
do_resource_copy(target, p("RobustToolbox", "Resources"), zipf, SHARED_IGNORED_RESOURCES)
for folder in LAUNCHER_RESOURCES:
copy_dir_into_zip(p("Resources", folder), p(target, folder), zipf)
def do_resource_copy(target, source, zipf, ignore_set):
for filename in os.listdir(source):
if filename in ignore_set:
2019-03-21 21:19:18 +01:00
continue
path = p(source, filename)
target_path = p(target, filename)
if os.path.isdir(path):
copy_dir_into_zip(path, target_path, zipf)
2017-08-14 15:05:39 +02:00
else:
zipf.write(path, target_path)
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):
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)
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)
2017-08-06 23:15:39 +02:00
2019-03-21 21:19:18 +01:00
def copy_content_assemblies(target, zipf, server):
if server:
source_dir = p("bin", "Content.Server")
files = ["Content.Shared.dll", "Content.Server.dll"] + SERVER_EXTRA_CONTENT_ASSEMBLIES
for filename in os.listdir(source_dir):
2020-01-24 20:48:24 +01:00
if filename.startswith("Microsoft.") or filename.startswith("Npgsql."):
files.append(filename)
2019-03-21 21:19:18 +01:00
else:
source_dir = p("bin", "Content.Client")
files = ["Content.Shared.dll", "Content.Client.dll"]
# Write assemblies dir if necessary.
if not zip_entry_exists(zipf, target):
zipf.write(".", target)
for x in files:
zipf.write(p(source_dir, x), p(target, x))
2019-12-16 00:46:09 +01:00
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))
2020-04-27 11:32:05 +02:00
2019-12-16 00:46:09 +01:00
def copy_client_natives(fileNames: List[str], zipf: zipfile.ZipFile, zipPath: str):
for fileName in fileNames:
zipf.write(p("RobustToolbox", "bin", "Client", fileName), p(zipPath, fileName))
print(f"writing native {fileName}")
2020-04-27 11:32:05 +02:00
2017-08-06 23:15:39 +02:00
if __name__ == '__main__':
main()