mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-19 21:37:57 +08:00
205 lines
7.2 KiB
Python
Executable File
205 lines
7.2 KiB
Python
Executable File
# Released under the MIT License. See LICENSE for details.
|
|
#
|
|
"""Utils for wrangling running the app as part of a build.
|
|
|
|
Manages constructing or downloading it as well as running it.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import TYPE_CHECKING
|
|
import platform
|
|
import subprocess
|
|
import os
|
|
|
|
from efro.terminal import Clr
|
|
|
|
if TYPE_CHECKING:
|
|
from typing import Mapping
|
|
|
|
|
|
def test_runs_disabled() -> bool:
|
|
"""Are test runs disabled on the current platform?"""
|
|
|
|
# Currently skipping this on Windows, as we aren't able to assemble
|
|
# complete build there without WSL.
|
|
if platform.system() == 'Windows':
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
def test_runs_disabled_reason() -> str:
|
|
"""Why are test runs disabled here?"""
|
|
# Can get more specific later.
|
|
return 'App test runs disabled here.'
|
|
|
|
|
|
def acquire_binary_for_python_command(purpose: str) -> str:
|
|
"""Run acquire_binary as used for python_command call."""
|
|
return acquire_binary(assets=True, purpose=purpose)
|
|
|
|
|
|
def python_command(
|
|
cmd: str,
|
|
purpose: str,
|
|
include_project_tools: bool = False,
|
|
env: Mapping[str, str] | None = None,
|
|
) -> None:
|
|
"""Run a cmd with a built bin and PYTHONPATH set to its scripts."""
|
|
|
|
binpath = acquire_binary_for_python_command(purpose=purpose)
|
|
bindir = os.path.dirname(binpath)
|
|
|
|
# We'll set both the app python dir and its site-python-dir. This
|
|
# should let us get at most engine stuff. We could also just use
|
|
# baenv to set up app paths, but that might be overkill and could
|
|
# unintentionally bring in stuff like local mods.
|
|
pydir = f'{bindir}/ba_data/python'
|
|
assert os.path.isdir(pydir)
|
|
pysitedir = f'{bindir}/ba_data/python-site-packages'
|
|
assert os.path.isdir(pysitedir)
|
|
|
|
# Make our tools dir available if asked.
|
|
tools_path_extra = ':tools' if include_project_tools else ''
|
|
|
|
env_final = {} if env is None else dict(env)
|
|
env_final['PYTHONPATH'] = f'{pydir}:{pysitedir}{tools_path_extra}'
|
|
|
|
cmdargs = [binpath, '--command', cmd]
|
|
print(f"apprun: Running with Python command: '{cmdargs}'...", flush=True)
|
|
subprocess.run(cmdargs, env=env_final, check=True)
|
|
|
|
|
|
def acquire_binary(assets: bool, purpose: str) -> str:
|
|
"""Return path to a runnable binary, building/downloading as needed.
|
|
|
|
If 'assets' is False, only the binary itself will be fetched or
|
|
assembled; no scripts or assets. This generally saves some time, but
|
|
must only be used for very simple '-c' command cases where no assets
|
|
will be needed.
|
|
|
|
Be aware that it is up to the particular environment whether a gui
|
|
or headless binary will be provided. Commands should be designed to
|
|
work with either.
|
|
|
|
By default, downloaded prefab builds will be used here. This allows
|
|
people without full compiler setups to still perform app runs for
|
|
things like dummy-module generation. However, someone who *is* able
|
|
to compile their own binaries might prefer to use their own binaries
|
|
here so that changes to their local repo are properly reflected in
|
|
app runs and whatnot. Set environment variable
|
|
BA_APP_RUN_ENABLE_BUILDS=1 to enable that.
|
|
|
|
When local builds are enabled, we use the same gui build targets as
|
|
the 'make cmake-build' command. This works well if you are iterating
|
|
using that build target anyway, minimizing redundant rebuilds. You
|
|
may, however, prefer to instead assemble headless builds for various
|
|
reasons including faster build times and fewer dependencies
|
|
(equivalent to 'make cmake-server-build'). To do so, set environment
|
|
variable BA_APP_RUN_BUILD_HEADLESS=1.
|
|
"""
|
|
import textwrap
|
|
|
|
binary_build_command: list[str]
|
|
if os.environ.get('BA_APP_RUN_ENABLE_BUILDS') == '1':
|
|
# Going the build-it-ourselves route.
|
|
|
|
# Don't need any env mods for this path.
|
|
env = None
|
|
|
|
if os.environ.get('BA_APP_RUN_BUILD_HEADLESS') == '1':
|
|
# User has opted for headless builds.
|
|
if assets:
|
|
print(
|
|
f'{Clr.SMAG}Building headless binary & assets for'
|
|
f' {purpose}...{Clr.RST}',
|
|
flush=True,
|
|
)
|
|
binary_build_command = ['make', 'cmake-server-build']
|
|
else:
|
|
print(
|
|
f'{Clr.SMAG}Building headless binary for'
|
|
f' {purpose}...{Clr.RST}',
|
|
flush=True,
|
|
)
|
|
binary_build_command = ['make', 'cmake-server-binary']
|
|
binary_path = (
|
|
'build/cmake/server-debug/staged/dist/ballisticakit_headless'
|
|
)
|
|
else:
|
|
# Using default gui builds.
|
|
if assets:
|
|
print(
|
|
f'{Clr.SMAG}Building gui binary & assets for'
|
|
f' {purpose}...{Clr.RST}',
|
|
flush=True,
|
|
)
|
|
binary_build_command = ['make', 'cmake-build']
|
|
else:
|
|
print(
|
|
f'{Clr.SMAG}Building gui binary for {purpose}...{Clr.RST}',
|
|
flush=True,
|
|
)
|
|
binary_build_command = ['make', 'cmake-binary']
|
|
binary_path = 'build/cmake/debug/staged/ballisticakit'
|
|
else:
|
|
# Ok; going with a downloaded prefab headless build.
|
|
|
|
# By default, prefab build targets on WSL (Linux running on
|
|
# Windows) will give us Windows builds which won't work right
|
|
# here. Ask it for Linux builds instead.
|
|
env = dict(os.environ, BA_WSL_TARGETS_WINDOWS='0')
|
|
|
|
# Let the user know how to use their own built binaries instead
|
|
# if they prefer.
|
|
note = '\n' + textwrap.fill(
|
|
f'NOTE: You can set env-var BA_APP_RUN_ENABLE_BUILDS=1'
|
|
f' to use locally-built binaries for {purpose} instead'
|
|
f' of prefab ones. This will properly reflect any changes'
|
|
f' you\'ve made to the C/C++ layer.',
|
|
80,
|
|
)
|
|
|
|
if assets:
|
|
print(
|
|
f'{Clr.SMAG}Fetching prefab binary & assets for'
|
|
f' {purpose}...{note}{Clr.RST}',
|
|
flush=True,
|
|
)
|
|
binary_path = (
|
|
subprocess.run(
|
|
['tools/pcommand', 'prefab_binary_path', 'server-release'],
|
|
env=env,
|
|
check=True,
|
|
capture_output=True,
|
|
)
|
|
.stdout.decode()
|
|
.strip()
|
|
)
|
|
binary_build_command = ['make', 'prefab-server-release-build']
|
|
else:
|
|
print(
|
|
f'{Clr.SMAG}Fetching prefab binary for {purpose}...'
|
|
f'{note}{Clr.RST}',
|
|
flush=True,
|
|
)
|
|
binary_path = (
|
|
subprocess.run(
|
|
['tools/pcommand', 'prefab_binary_path', 'server-release'],
|
|
env=env,
|
|
check=True,
|
|
capture_output=True,
|
|
)
|
|
.stdout.decode()
|
|
.strip()
|
|
)
|
|
binary_build_command = ['make', binary_path]
|
|
|
|
subprocess.run(binary_build_command, env=env, check=True)
|
|
if not os.path.exists(binary_path):
|
|
raise RuntimeError(
|
|
f"Binary not found at expected path '{binary_path}'."
|
|
)
|
|
return binary_path
|