Spaces:
Sleeping
Sleeping
| import glob | |
| import os | |
| import subprocess | |
| from sys import platform | |
| from typing import Optional, List | |
| from mlagents_envs.logging_util import get_logger, DEBUG | |
| from mlagents_envs.exception import UnityEnvironmentException | |
| logger = get_logger(__name__) | |
| def get_platform(): | |
| """ | |
| returns the platform of the operating system : linux, darwin or win32 | |
| """ | |
| return platform | |
| def validate_environment_path(env_path: str) -> Optional[str]: | |
| """ | |
| Strip out executable extensions of the env_path | |
| :param env_path: The path to the executable | |
| """ | |
| env_path = ( | |
| env_path.strip() | |
| .replace(".app", "") | |
| .replace(".exe", "") | |
| .replace(".x86_64", "") | |
| .replace(".x86", "") | |
| ) | |
| true_filename = os.path.basename(os.path.normpath(env_path)) | |
| logger.debug(f"The true file name is {true_filename}") | |
| if not (glob.glob(env_path) or glob.glob(env_path + ".*")): | |
| return None | |
| cwd = os.getcwd() | |
| launch_string = None | |
| true_filename = os.path.basename(os.path.normpath(env_path)) | |
| if get_platform() == "linux" or get_platform() == "linux2": | |
| candidates = glob.glob(os.path.join(cwd, env_path) + ".x86_64") | |
| if len(candidates) == 0: | |
| candidates = glob.glob(os.path.join(cwd, env_path) + ".x86") | |
| if len(candidates) == 0: | |
| candidates = glob.glob(env_path + ".x86_64") | |
| if len(candidates) == 0: | |
| candidates = glob.glob(env_path + ".x86") | |
| if len(candidates) == 0: | |
| if os.path.isfile(env_path): | |
| candidates = [env_path] | |
| if len(candidates) > 0: | |
| launch_string = candidates[0] | |
| elif get_platform() == "darwin": | |
| candidates = glob.glob( | |
| os.path.join(cwd, env_path + ".app", "Contents", "MacOS", true_filename) | |
| ) | |
| if len(candidates) == 0: | |
| candidates = glob.glob( | |
| os.path.join(env_path + ".app", "Contents", "MacOS", true_filename) | |
| ) | |
| if len(candidates) == 0: | |
| candidates = glob.glob( | |
| os.path.join(cwd, env_path + ".app", "Contents", "MacOS", "*") | |
| ) | |
| if len(candidates) == 0: | |
| candidates = glob.glob( | |
| os.path.join(env_path + ".app", "Contents", "MacOS", "*") | |
| ) | |
| if len(candidates) > 0: | |
| launch_string = candidates[0] | |
| elif get_platform() == "win32": | |
| candidates = glob.glob(os.path.join(cwd, env_path + ".exe")) | |
| if len(candidates) == 0: | |
| candidates = glob.glob(env_path + ".exe") | |
| if len(candidates) == 0: | |
| # Look for e.g. 3DBall\UnityEnvironment.exe | |
| crash_handlers = set( | |
| glob.glob(os.path.join(cwd, env_path, "UnityCrashHandler*.exe")) | |
| ) | |
| candidates = [ | |
| c | |
| for c in glob.glob(os.path.join(cwd, env_path, "*.exe")) | |
| if c not in crash_handlers | |
| ] | |
| if len(candidates) > 0: | |
| launch_string = candidates[0] | |
| return launch_string | |
| def launch_executable(file_name: str, args: List[str]) -> subprocess.Popen: | |
| """ | |
| Launches a Unity executable and returns the process handle for it. | |
| :param file_name: the name of the executable | |
| :param args: List of string that will be passed as command line arguments | |
| when launching the executable. | |
| """ | |
| launch_string = validate_environment_path(file_name) | |
| if launch_string is None: | |
| raise UnityEnvironmentException( | |
| f"Couldn't launch the {file_name} environment. Provided filename does not match any environments." | |
| ) | |
| else: | |
| logger.debug(f"The launch string is {launch_string}") | |
| logger.debug(f"Running with args {args}") | |
| # Launch Unity environment | |
| subprocess_args = [launch_string] + args | |
| # std_out_option = DEVNULL means the outputs will not be displayed on terminal. | |
| # std_out_option = None is default behavior: the outputs are displayed on terminal. | |
| std_out_option = subprocess.DEVNULL if logger.level > DEBUG else None | |
| try: | |
| return subprocess.Popen( | |
| subprocess_args, | |
| # start_new_session=True means that signals to the parent python process | |
| # (e.g. SIGINT from keyboard interrupt) will not be sent to the new process on POSIX platforms. | |
| # This is generally good since we want the environment to have a chance to shutdown, | |
| # but may be undesirable in come cases; if so, we'll add a command-line toggle. | |
| # Note that on Windows, the CTRL_C signal will still be sent. | |
| start_new_session=True, | |
| stdout=std_out_option, | |
| stderr=std_out_option, | |
| ) | |
| except PermissionError as perm: | |
| # This is likely due to missing read or execute permissions on file. | |
| raise UnityEnvironmentException( | |
| f"Error when trying to launch environment - make sure " | |
| f"permissions are set correctly. For example " | |
| f'"chmod -R 755 {launch_string}"' | |
| ) from perm | |