147 lines
4.5 KiB
Python
147 lines
4.5 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""Erlang and build-tool command resolution."""
|
||
|
||
from .shared import *
|
||
|
||
def get_erl_cmd(erl_path: str = None) -> str:
|
||
"""根据配置路径获取 erl 可执行文件路径
|
||
|
||
Args:
|
||
erl_path: Erlang 安装根目录(如 E:/app/erlang/Erlang_OTP_25)
|
||
|
||
Returns:
|
||
erl 可执行文件的完整路径,或默认的 'erl'
|
||
"""
|
||
if erl_path and erl_path.strip():
|
||
if IS_WINDOWS:
|
||
erl_exe = Path(erl_path.strip()) / 'bin' / 'erl.exe'
|
||
if erl_exe.exists():
|
||
return str(erl_exe)
|
||
else:
|
||
erl_bin = Path(erl_path.strip()) / 'bin' / 'erl'
|
||
if erl_bin.exists():
|
||
return str(erl_bin)
|
||
return 'erl'
|
||
|
||
|
||
def subprocess_args_to_display(args: List[str]) -> str:
|
||
"""将 subprocess 参数列表转为可读的命令字符串(仅用于显示/日志)"""
|
||
parts = []
|
||
for a in args:
|
||
if ' ' in a or '"' in a or "'" in a or any(c in a for c in '()[]{}&|<>^'):
|
||
parts.append(f'"{a}"')
|
||
else:
|
||
parts.append(a)
|
||
return ' '.join(parts)
|
||
|
||
|
||
def get_escript_cmd(erl_path: str = None) -> str:
|
||
"""根据配置路径获取 escript 可执行文件路径
|
||
|
||
Args:
|
||
erl_path: Erlang 安装根目录
|
||
|
||
Returns:
|
||
escript 可执行文件的完整路径,或默认的 'escript'
|
||
"""
|
||
if erl_path and erl_path.strip():
|
||
if IS_WINDOWS:
|
||
escript_exe = Path(erl_path.strip()) / 'bin' / 'escript.exe'
|
||
if escript_exe.exists():
|
||
return str(escript_exe)
|
||
else:
|
||
escript_bin = Path(erl_path.strip()) / 'bin' / 'escript'
|
||
if escript_bin.exists():
|
||
return str(escript_bin)
|
||
return 'escript'
|
||
|
||
|
||
def _ensure_epmd_daemon(erl_path: Optional[str] = None) -> None:
|
||
"""尽量执行 epmd -daemon。本机已有 epmd 时通常无害(就绪则不再重复监听)。"""
|
||
erl_exe = Path(get_erl_cmd(erl_path))
|
||
epmd = erl_exe.parent / ("epmd.exe" if IS_WINDOWS else "epmd")
|
||
if not epmd.is_file():
|
||
which = shutil.which("epmd")
|
||
if not which:
|
||
return
|
||
epmd = Path(which)
|
||
try:
|
||
subprocess.run(
|
||
[str(epmd), "-daemon"],
|
||
capture_output=True,
|
||
timeout=5,
|
||
creationflags=getattr(subprocess, "CREATE_NO_WINDOW", 0) if IS_WINDOWS else 0,
|
||
)
|
||
except Exception:
|
||
pass
|
||
|
||
|
||
def get_rebar3_cmd(server_root: str, erl_path: str = None) -> str:
|
||
"""获取 rebar3 执行命令
|
||
|
||
如果配置了 erl_path,直接用配置路径的 escript 来运行 rebar3 脚本,
|
||
而不是依赖系统 PATH 中的 escript。
|
||
|
||
Args:
|
||
server_root: 服务器根目录(rebar3 脚本所在目录)
|
||
erl_path: Erlang 安装根目录
|
||
|
||
Returns:
|
||
rebar3 执行命令字符串
|
||
"""
|
||
escript = get_escript_cmd(erl_path)
|
||
if IS_WINDOWS:
|
||
rebar3_script = Path(server_root) / 'rebar3'
|
||
if escript != 'escript':
|
||
return f'"{escript}" "{rebar3_script}"'
|
||
return REBAR3_CMD
|
||
else:
|
||
rebar3_script = Path(server_root) / 'rebar3'
|
||
if escript != 'escript':
|
||
return f'"{escript}" "{rebar3_script}"'
|
||
return './rebar3'
|
||
|
||
|
||
def get_local_ip() -> str:
|
||
"""获取本机IP地址"""
|
||
try:
|
||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||
s.connect(("8.8.8.8", 80))
|
||
ip = s.getsockname()[0]
|
||
s.close()
|
||
return ip
|
||
except:
|
||
return "127.0.0.1"
|
||
|
||
|
||
def get_ebin_paths(server_root: str, profile: str = 'game_server_dev') -> List[str]:
|
||
"""获取所有 ebin 目录路径
|
||
|
||
Args:
|
||
server_root: 服务器根目录
|
||
profile: rebar3 profile 名称 (game_server_dev/login_server_dev/client_server_dev)
|
||
|
||
Returns:
|
||
ebin 目录路径列表
|
||
"""
|
||
ebin_paths = []
|
||
build_dir = Path(server_root) / "_build" / profile / "lib"
|
||
|
||
if build_dir.exists():
|
||
for app_dir in build_dir.iterdir():
|
||
if app_dir.is_dir():
|
||
ebin_dir = app_dir / "ebin"
|
||
if ebin_dir.exists():
|
||
ebin_paths.append(str(ebin_dir))
|
||
|
||
# 添加 checkouts 目录
|
||
checkouts_dir = Path(server_root) / "_build" / profile / "checkouts"
|
||
if checkouts_dir.exists():
|
||
for app_dir in checkouts_dir.iterdir():
|
||
if app_dir.is_dir():
|
||
ebin_dir = app_dir / "ebin"
|
||
if ebin_dir.exists():
|
||
ebin_paths.append(str(ebin_dir))
|
||
|
||
return ebin_paths
|