Removes `copy_godot_scenes` which copies the files from Resources/Scenes into the release package folder. This function breaks builds with the latest commit #220 as it removed the remaining scene (tscn) files from the content repo and deleted the Scenes folder.
290 lines
9.3 KiB
Python
Executable File
290 lines
9.3 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# Packages a full release build that can be unzipped and you'll have your SS14 client or server.
|
|
|
|
import os
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import zipfile
|
|
import argparse
|
|
|
|
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
|
|
|
|
SHARED_IGNORED_RESOURCES = {
|
|
"ss13model.7z",
|
|
"ResourcePack.zip",
|
|
"buildResourcePack.py",
|
|
"CONTENT_GOES_HERE",
|
|
".gitignore"
|
|
}
|
|
CLIENT_IGNORED_RESOURCES = {
|
|
"Maps",
|
|
"emotes.xml",
|
|
"Groups"
|
|
}
|
|
SERVER_IGNORED_RESOURCES = {
|
|
"Textures",
|
|
"Fonts",
|
|
"Audio",
|
|
"Scenes",
|
|
"Nano",
|
|
"Shaders",
|
|
}
|
|
|
|
def main():
|
|
global GODOT
|
|
parser = argparse.ArgumentParser(
|
|
description="Packages the SS14 content repo for release on all platforms.")
|
|
parser.add_argument("--platform",
|
|
"-p",
|
|
action="store",
|
|
choices=["windows", "mac", "linux"],
|
|
nargs="*",
|
|
help="Which platform to build for. If not provided, all platforms will be built")
|
|
|
|
args = parser.parse_args()
|
|
platforms = args.platform
|
|
if not platforms:
|
|
platforms = ["windows", "mac", "linux"]
|
|
|
|
if os.path.exists("release"):
|
|
print(Fore.BLUE + Style.DIM +
|
|
"Cleaning old release packages (release/)..." + Style.RESET_ALL)
|
|
shutil.rmtree("release")
|
|
|
|
os.mkdir("release")
|
|
|
|
if "windows" in platforms:
|
|
wipe_bin()
|
|
build_windows()
|
|
|
|
if "linux" in platforms:
|
|
wipe_bin()
|
|
build_linux()
|
|
|
|
if "mac" in platforms:
|
|
wipe_bin()
|
|
build_macos()
|
|
|
|
|
|
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"))
|
|
|
|
if os.path.exists("bin"):
|
|
shutil.rmtree("bin")
|
|
|
|
|
|
def build_windows():
|
|
# Run a full build.
|
|
print(Fore.GREEN + "Building project for Windows x64..." + Style.RESET_ALL)
|
|
subprocess.run(["msbuild",
|
|
"SpaceStation14.sln",
|
|
"/m",
|
|
"/p:Configuration=Release",
|
|
"/p:Platform=x64",
|
|
"/nologo",
|
|
"/v:m",
|
|
"/p:TargetOS=Windows",
|
|
"/t:Rebuild"
|
|
], check=True)
|
|
|
|
print(Fore.GREEN + "Packaging Windows x64 client..." + Style.RESET_ALL)
|
|
|
|
client_zip = zipfile.ZipFile(
|
|
p("release", "SS14.Client_Windows_x64.zip"), "w",
|
|
compression=zipfile.ZIP_DEFLATED)
|
|
|
|
copy_dir_into_zip(p("RobustToolbox", "bin", "Client"), "", client_zip)
|
|
copy_resources("Resources", client_zip, server=False)
|
|
copy_content_assemblies(p("Resources", "Assemblies"), client_zip, server=False)
|
|
# Cool we're done.
|
|
client_zip.close()
|
|
|
|
print(Fore.GREEN + "Packaging Windows x64 server..." + Style.RESET_ALL)
|
|
server_zip = zipfile.ZipFile(p("release", "SS14.Server_Windows_x64.zip"), "w",
|
|
compression=zipfile.ZIP_DEFLATED)
|
|
copy_dir_into_zip(p("RobustToolbox", "bin", "Server"), "", server_zip)
|
|
copy_resources(p("Resources"), server_zip, server=True)
|
|
copy_content_assemblies(p("Resources", "Assemblies"), server_zip, server=True)
|
|
server_zip.close()
|
|
|
|
|
|
def build_macos():
|
|
print(Fore.GREEN + "Building project for macOS x64..." + Style.RESET_ALL)
|
|
subprocess.run(["msbuild",
|
|
"SpaceStation14.sln",
|
|
"/m",
|
|
"/p:Configuration=Release",
|
|
"/p:Platform=x64",
|
|
"/nologo",
|
|
"/v:m",
|
|
"/p:TargetOS=MacOS",
|
|
"/t:Rebuild"
|
|
], check=True)
|
|
|
|
print(Fore.GREEN + "Packaging macOS x64 client..." + Style.RESET_ALL)
|
|
# Client has to go in an app bundle.
|
|
client_zip = zipfile.ZipFile(p("release", "SS14.Client_macOS_x64.zip"), "a",
|
|
compression=zipfile.ZIP_DEFLATED)
|
|
|
|
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)
|
|
copy_dir_into_zip(p("RobustToolbox", "bin", "Client"), contents, client_zip)
|
|
|
|
copy_resources(p(contents, "Resources"), client_zip, server=False)
|
|
copy_content_assemblies(p(contents, "Resources", "Assemblies"), client_zip, server=False)
|
|
client_zip.close()
|
|
|
|
print(Fore.GREEN + "Packaging macOS x64 server..." + Style.RESET_ALL)
|
|
server_zip = zipfile.ZipFile(p("release", "SS14.Server_macOS_x64.zip"), "w",
|
|
compression=zipfile.ZIP_DEFLATED)
|
|
copy_dir_into_zip(p("RobustToolbox", "bin", "Server"), "", server_zip)
|
|
copy_resources(p("Resources"), server_zip, server=True)
|
|
copy_content_assemblies(p("Resources", "Assemblies"), server_zip, server=True)
|
|
server_zip.close()
|
|
|
|
|
|
def build_linux():
|
|
# Run a full build.
|
|
print(Fore.GREEN + "Building project for Linux x64..." + Style.RESET_ALL)
|
|
subprocess.run(["msbuild",
|
|
"SpaceStation14.sln",
|
|
"/m",
|
|
"/p:Configuration=Release",
|
|
"/p:Platform=x64",
|
|
"/nologo",
|
|
"/v:m",
|
|
"/p:TargetOS=Linux",
|
|
"/t:Rebuild"
|
|
], check=True)
|
|
|
|
print(Fore.GREEN + "Packaging Linux x64 client..." + Style.RESET_ALL)
|
|
|
|
client_zip = zipfile.ZipFile(
|
|
p("release", "SS14.Client_Linux_x64.zip"), "w",
|
|
compression=zipfile.ZIP_DEFLATED)
|
|
|
|
copy_dir_into_zip(p("RobustToolbox", "bin", "Client"), "", client_zip)
|
|
copy_resources("Resources", client_zip, server=False)
|
|
copy_content_assemblies(p("Resources", "Assemblies"), client_zip, server=False)
|
|
# Cool we're done.
|
|
client_zip.close()
|
|
|
|
print(Fore.GREEN + "Packaging Linux x64 server..." + Style.RESET_ALL)
|
|
server_zip = zipfile.ZipFile(p("release", "SS14.Server_Linux_x64.zip"), "w",
|
|
compression=zipfile.ZIP_DEFLATED)
|
|
copy_dir_into_zip(p("RobustToolbox", "bin", "Server"), "", server_zip)
|
|
copy_resources(p("Resources"), server_zip, server=True)
|
|
copy_content_assemblies(p("Resources", "Assemblies"), server_zip, server=True)
|
|
server_zip.close()
|
|
|
|
|
|
def copy_resources(target, zipf, server):
|
|
# Content repo goes FIRST so that it won't override engine files as that's forbidden.
|
|
do_resource_copy(target, "Resources", zipf, server)
|
|
do_resource_copy(target, p("RobustToolbox", "Resources"), zipf, server)
|
|
|
|
|
|
def do_resource_copy(target, source, zipf, server):
|
|
for filename in os.listdir(source):
|
|
if filename in SHARED_IGNORED_RESOURCES \
|
|
or filename in (SERVER_IGNORED_RESOURCES if server else CLIENT_IGNORED_RESOURCES):
|
|
continue
|
|
|
|
# Get rid of Godot .import files, thanks.
|
|
if filename.endswith(".import"):
|
|
continue
|
|
|
|
path = p(source, filename)
|
|
target_path = p(target, filename)
|
|
if os.path.isdir(path):
|
|
copy_dir_into_zip(path, target_path, zipf)
|
|
|
|
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)
|
|
|
|
|
|
def copy_content_assemblies(target, zipf, server):
|
|
if server:
|
|
source_dir = p("bin", "Content.Server")
|
|
files = ["Content.Shared.dll", "Content.Server.dll"]
|
|
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))
|
|
|
|
|
|
def copy_dir_or_file(src, dst):
|
|
"""
|
|
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()
|