mirror of
https://github.com/godotengine/godot.git
synced 2025-04-19 01:27:45 +08:00
Merge pull request #104617 from Repiteo/scons/color-refactor
SCons: Refactor `color.py`
This commit is contained in:
commit
3886fd1422
@ -58,7 +58,7 @@ import gles3_builders
|
||||
import glsl_builders
|
||||
import methods
|
||||
import scu_builders
|
||||
from misc.utility.color import STDERR_COLOR, print_error, print_info, print_warning
|
||||
from misc.utility.color import is_stderr_color, print_error, print_info, print_warning
|
||||
from platform_methods import architecture_aliases, architectures, compatibility_platform_aliases
|
||||
|
||||
if ARGUMENTS.get("target", "editor") == "editor":
|
||||
@ -704,9 +704,9 @@ if env["arch"] == "x86_32":
|
||||
|
||||
# Explicitly specify colored output.
|
||||
if methods.using_gcc(env):
|
||||
env.AppendUnique(CCFLAGS=["-fdiagnostics-color" if STDERR_COLOR else "-fno-diagnostics-color"])
|
||||
env.AppendUnique(CCFLAGS=["-fdiagnostics-color" if is_stderr_color() else "-fno-diagnostics-color"])
|
||||
elif methods.using_clang(env) or methods.using_emcc(env):
|
||||
env.AppendUnique(CCFLAGS=["-fcolor-diagnostics" if STDERR_COLOR else "-fno-color-diagnostics"])
|
||||
env.AppendUnique(CCFLAGS=["-fcolor-diagnostics" if is_stderr_color() else "-fno-color-diagnostics"])
|
||||
if sys.platform == "win32":
|
||||
env.AppendUnique(CCFLAGS=["-fansi-escape-codes"])
|
||||
|
||||
|
@ -10,14 +10,14 @@ from typing import Dict, List, Set
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../"))
|
||||
|
||||
from misc.utility.color import NO_COLOR, STDOUT_COLOR, Ansi, toggle_color
|
||||
from misc.utility.color import Ansi, force_stdout_color, is_stdout_color
|
||||
|
||||
################################################################################
|
||||
# Config #
|
||||
################################################################################
|
||||
|
||||
flags = {
|
||||
"c": STDOUT_COLOR,
|
||||
"c": is_stdout_color(),
|
||||
"b": False,
|
||||
"g": False,
|
||||
"s": False,
|
||||
@ -114,7 +114,7 @@ def validate_tag(elem: ET.Element, tag: str) -> None:
|
||||
|
||||
|
||||
def color(color: str, string: str) -> str:
|
||||
if NO_COLOR:
|
||||
if not is_stdout_color():
|
||||
return string
|
||||
color_format = "".join([str(x) for x in colors[color]])
|
||||
return f"{color_format}{string}{Ansi.RESET}"
|
||||
@ -332,8 +332,7 @@ if flags["u"]:
|
||||
table_column_names.append("Docs URL")
|
||||
table_columns.append("url")
|
||||
|
||||
if flags["c"]:
|
||||
toggle_color(True)
|
||||
force_stdout_color(flags["c"])
|
||||
|
||||
################################################################################
|
||||
# Help #
|
||||
|
@ -13,7 +13,7 @@ from typing import Any, Dict, List, Optional, TextIO, Tuple, Union
|
||||
sys.path.insert(0, root_directory := os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../"))
|
||||
|
||||
import version
|
||||
from misc.utility.color import Ansi, toggle_color
|
||||
from misc.utility.color import Ansi, force_stderr_color, force_stdout_color
|
||||
|
||||
# $DOCS_URL/path/to/page.html(#fragment-tag)
|
||||
GODOT_DOCS_PATTERN = re.compile(r"^\$DOCS_URL/(.*)\.html(#.*)?$")
|
||||
@ -698,7 +698,8 @@ def main() -> None:
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.color:
|
||||
toggle_color(True)
|
||||
force_stdout_color(True)
|
||||
force_stderr_color(True)
|
||||
|
||||
# Retrieve heading translations for the given language.
|
||||
if not args.dry_run and args.lang != "en":
|
||||
|
@ -428,9 +428,9 @@ def use_windows_spawn_fix(self, platform=None):
|
||||
|
||||
|
||||
def no_verbose(env):
|
||||
from misc.utility.color import Ansi
|
||||
from misc.utility.color import Ansi, is_stdout_color
|
||||
|
||||
colors = [Ansi.BLUE, Ansi.BOLD, Ansi.REGULAR, Ansi.RESET]
|
||||
colors = [Ansi.BLUE, Ansi.BOLD, Ansi.REGULAR, Ansi.RESET] if is_stdout_color() else ["", "", "", ""]
|
||||
|
||||
# There is a space before "..." to ensure that source file names can be
|
||||
# Ctrl + clicked in the VS Code terminal.
|
||||
|
@ -8,7 +8,7 @@ import urllib.request
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../"))
|
||||
|
||||
from misc.utility.color import Ansi
|
||||
from misc.utility.color import Ansi, color_print
|
||||
|
||||
# Base Godot dependencies path
|
||||
# If cross-compiling (no LOCALAPPDATA), we install in `bin`
|
||||
@ -42,7 +42,7 @@ if not os.path.exists(deps_folder):
|
||||
os.makedirs(deps_folder)
|
||||
|
||||
# Mesa NIR
|
||||
print(f"{Ansi.BOLD}[1/3] Mesa NIR{Ansi.RESET}")
|
||||
color_print(f"{Ansi.BOLD}[1/3] Mesa NIR")
|
||||
if os.path.isfile(mesa_archive):
|
||||
os.remove(mesa_archive)
|
||||
print(f"Downloading Mesa NIR {mesa_filename} ...")
|
||||
@ -69,7 +69,7 @@ if dlltool == "":
|
||||
dlltool = shutil.which("x86_64-w64-mingw32-dlltool") or ""
|
||||
has_mingw = gendef != "" and dlltool != ""
|
||||
|
||||
print(f"{Ansi.BOLD}[2/3] WinPixEventRuntime{Ansi.RESET}")
|
||||
color_print(f"{Ansi.BOLD}[2/3] WinPixEventRuntime")
|
||||
if os.path.isfile(pix_archive):
|
||||
os.remove(pix_archive)
|
||||
print(f"Downloading WinPixEventRuntime {pix_version} ...")
|
||||
@ -100,7 +100,7 @@ else:
|
||||
print(f"WinPixEventRuntime {pix_version} installed successfully.\n")
|
||||
|
||||
# DirectX 12 Agility SDK
|
||||
print(f"{Ansi.BOLD}[3/3] DirectX 12 Agility SDK{Ansi.RESET}")
|
||||
color_print(f"{Ansi.BOLD}[3/3] DirectX 12 Agility SDK")
|
||||
if os.path.isfile(agility_sdk_archive):
|
||||
os.remove(agility_sdk_archive)
|
||||
print(f"Downloading DirectX 12 Agility SDK {agility_sdk_version} ...")
|
||||
@ -116,5 +116,5 @@ os.remove(agility_sdk_archive)
|
||||
print(f"DirectX 12 Agility SDK {agility_sdk_version} installed successfully.\n")
|
||||
|
||||
# Complete message
|
||||
print(f'{Ansi.GREEN}All Direct3D 12 SDK components were installed to "{deps_folder}" successfully!{Ansi.RESET}')
|
||||
print(f'{Ansi.GREEN}You can now build Godot with Direct3D 12 support enabled by running "scons d3d12=yes".{Ansi.RESET}')
|
||||
color_print(f'{Ansi.GREEN}All Direct3D 12 SDK components were installed to "{deps_folder}" successfully!')
|
||||
color_print(f'{Ansi.GREEN}You can now build Godot with Direct3D 12 support enabled by running "scons d3d12=yes".')
|
||||
|
@ -1,86 +1,58 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from enum import Enum
|
||||
from typing import Final
|
||||
|
||||
# Colors are disabled in non-TTY environments such as pipes. This means if output is redirected
|
||||
# to a file, it won't contain color codes. Colors are always enabled on continuous integration.
|
||||
# to a file, it won't contain color codes. Colors are enabled by default on continuous integration.
|
||||
|
||||
IS_CI: Final[bool] = bool(os.environ.get("CI"))
|
||||
NO_COLOR: Final[bool] = bool(os.environ.get("NO_COLOR"))
|
||||
CLICOLOR_FORCE: Final[bool] = bool(os.environ.get("CLICOLOR_FORCE"))
|
||||
STDOUT_TTY: Final[bool] = bool(sys.stdout.isatty())
|
||||
STDERR_TTY: Final[bool] = bool(sys.stderr.isatty())
|
||||
|
||||
|
||||
def _color_supported(stdout: bool) -> bool:
|
||||
_STDOUT_ORIGINAL: Final[bool] = False if NO_COLOR else CLICOLOR_FORCE or IS_CI or STDOUT_TTY
|
||||
_STDERR_ORIGINAL: Final[bool] = False if NO_COLOR else CLICOLOR_FORCE or IS_CI or STDERR_TTY
|
||||
_stdout_override: bool = _STDOUT_ORIGINAL
|
||||
_stderr_override: bool = _STDERR_ORIGINAL
|
||||
|
||||
|
||||
def is_stdout_color() -> bool:
|
||||
return _stdout_override
|
||||
|
||||
|
||||
def is_stderr_color() -> bool:
|
||||
return _stderr_override
|
||||
|
||||
|
||||
def force_stdout_color(value: bool) -> None:
|
||||
"""
|
||||
Validates if the current environment supports colored output. Attempts to enable ANSI escape
|
||||
code support on Windows 10 and later.
|
||||
Explicitly set `stdout` support for ANSI escape codes.
|
||||
If environment overrides exist, does nothing.
|
||||
"""
|
||||
if IS_CI:
|
||||
return True
|
||||
|
||||
if sys.platform != "win32":
|
||||
return STDOUT_TTY if stdout else STDERR_TTY
|
||||
else:
|
||||
from ctypes import POINTER, WINFUNCTYPE, WinError, windll
|
||||
from ctypes.wintypes import BOOL, DWORD, HANDLE
|
||||
|
||||
STD_HANDLE = -11 if stdout else -12
|
||||
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4
|
||||
|
||||
def err_handler(result, func, args):
|
||||
if not result:
|
||||
raise WinError()
|
||||
return args
|
||||
|
||||
GetStdHandle = WINFUNCTYPE(HANDLE, DWORD)(("GetStdHandle", windll.kernel32), ((1, "nStdHandle"),))
|
||||
GetConsoleMode = WINFUNCTYPE(BOOL, HANDLE, POINTER(DWORD))(
|
||||
("GetConsoleMode", windll.kernel32),
|
||||
((1, "hConsoleHandle"), (2, "lpMode")),
|
||||
)
|
||||
GetConsoleMode.errcheck = err_handler
|
||||
SetConsoleMode = WINFUNCTYPE(BOOL, HANDLE, DWORD)(
|
||||
("SetConsoleMode", windll.kernel32),
|
||||
((1, "hConsoleHandle"), (1, "dwMode")),
|
||||
)
|
||||
SetConsoleMode.errcheck = err_handler
|
||||
|
||||
try:
|
||||
handle = GetStdHandle(STD_HANDLE)
|
||||
flags = GetConsoleMode(handle)
|
||||
SetConsoleMode(handle, flags | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
|
||||
return True
|
||||
except OSError:
|
||||
return False
|
||||
|
||||
|
||||
STDOUT_COLOR: Final[bool] = _color_supported(True)
|
||||
STDERR_COLOR: Final[bool] = _color_supported(False)
|
||||
_stdout_override: bool = STDOUT_COLOR
|
||||
_stderr_override: bool = STDERR_COLOR
|
||||
|
||||
|
||||
def toggle_color(stdout: bool, value: bool | None = None) -> None:
|
||||
"""
|
||||
Explicitly toggle color codes, regardless of support.
|
||||
|
||||
- `stdout`: A boolean to choose the output stream. `True` for stdout, `False` for stderr.
|
||||
- `value`: An optional boolean to explicitly set the color state instead of toggling.
|
||||
"""
|
||||
if stdout:
|
||||
if not NO_COLOR or not CLICOLOR_FORCE:
|
||||
global _stdout_override
|
||||
_stdout_override = value if value is not None else not _stdout_override
|
||||
else:
|
||||
_stdout_override = value
|
||||
|
||||
|
||||
def force_stderr_color(value: bool) -> None:
|
||||
"""
|
||||
Explicitly set `stderr` support for ANSI escape codes.
|
||||
If environment overrides exist, does nothing.
|
||||
"""
|
||||
if not NO_COLOR or not CLICOLOR_FORCE:
|
||||
global _stderr_override
|
||||
_stderr_override = value if value is not None else not _stderr_override
|
||||
_stderr_override = value
|
||||
|
||||
|
||||
class Ansi(Enum):
|
||||
"""
|
||||
Enum class for adding ansi codepoints directly into strings. Automatically converts values to
|
||||
Enum class for adding ANSI codepoints directly into strings. Automatically converts values to
|
||||
strings representing their internal value.
|
||||
"""
|
||||
|
||||
@ -107,25 +79,74 @@ class Ansi(Enum):
|
||||
return self.value
|
||||
|
||||
|
||||
RE_ANSI = re.compile(r"\x1b\[[=\?]?[;\d]+[a-zA-Z]")
|
||||
|
||||
|
||||
def color_print(*values: object, sep: str | None = " ", end: str | None = "\n", flush: bool = False) -> None:
|
||||
"""Prints a colored message to `stdout`. If disabled, ANSI codes are automatically stripped."""
|
||||
if is_stdout_color():
|
||||
print(*values, sep=sep, end=f"{Ansi.RESET}{end}", flush=flush)
|
||||
else:
|
||||
print(RE_ANSI.sub("", (sep or " ").join(map(str, values))), sep="", end=end, flush=flush)
|
||||
|
||||
|
||||
def color_printerr(*values: object, sep: str | None = " ", end: str | None = "\n", flush: bool = False) -> None:
|
||||
"""Prints a colored message to `stderr`. If disabled, ANSI codes are automatically stripped."""
|
||||
if is_stderr_color():
|
||||
print(*values, sep=sep, end=f"{Ansi.RESET}{end}", flush=flush, file=sys.stderr)
|
||||
else:
|
||||
print(RE_ANSI.sub("", (sep or " ").join(map(str, values))), sep="", end=end, flush=flush, file=sys.stderr)
|
||||
|
||||
|
||||
def print_info(*values: object) -> None:
|
||||
"""Prints a informational message with formatting."""
|
||||
if _stdout_override:
|
||||
print(f"{Ansi.GRAY}{Ansi.BOLD}INFO:{Ansi.REGULAR}", *values, Ansi.RESET)
|
||||
else:
|
||||
print("INFO:", *values)
|
||||
color_print(f"{Ansi.GRAY}{Ansi.BOLD}INFO:{Ansi.REGULAR}", *values)
|
||||
|
||||
|
||||
def print_warning(*values: object) -> None:
|
||||
"""Prints a warning message with formatting."""
|
||||
if _stderr_override:
|
||||
print(f"{Ansi.YELLOW}{Ansi.BOLD}WARNING:{Ansi.REGULAR}", *values, Ansi.RESET, file=sys.stderr)
|
||||
else:
|
||||
print("WARNING:", *values, file=sys.stderr)
|
||||
color_printerr(f"{Ansi.YELLOW}{Ansi.BOLD}WARNING:{Ansi.REGULAR}", *values)
|
||||
|
||||
|
||||
def print_error(*values: object) -> None:
|
||||
"""Prints an error message with formatting."""
|
||||
if _stderr_override:
|
||||
print(f"{Ansi.RED}{Ansi.BOLD}ERROR:{Ansi.REGULAR}", *values, Ansi.RESET, file=sys.stderr)
|
||||
else:
|
||||
print("ERROR:", *values, file=sys.stderr)
|
||||
color_printerr(f"{Ansi.RED}{Ansi.BOLD}ERROR:{Ansi.REGULAR}", *values)
|
||||
|
||||
|
||||
if sys.platform == "win32":
|
||||
|
||||
def _win_color_fix():
|
||||
"""Attempts to enable ANSI escape code support on Windows 10 and later."""
|
||||
from ctypes import POINTER, WINFUNCTYPE, WinError, windll
|
||||
from ctypes.wintypes import BOOL, DWORD, HANDLE
|
||||
|
||||
STDOUT_HANDLE = -11
|
||||
STDERR_HANDLE = -12
|
||||
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4
|
||||
|
||||
def err_handler(result, func, args):
|
||||
if not result:
|
||||
raise WinError()
|
||||
return args
|
||||
|
||||
GetStdHandle = WINFUNCTYPE(HANDLE, DWORD)(("GetStdHandle", windll.kernel32), ((1, "nStdHandle"),))
|
||||
GetConsoleMode = WINFUNCTYPE(BOOL, HANDLE, POINTER(DWORD))(
|
||||
("GetConsoleMode", windll.kernel32),
|
||||
((1, "hConsoleHandle"), (2, "lpMode")),
|
||||
)
|
||||
GetConsoleMode.errcheck = err_handler
|
||||
SetConsoleMode = WINFUNCTYPE(BOOL, HANDLE, DWORD)(
|
||||
("SetConsoleMode", windll.kernel32),
|
||||
((1, "hConsoleHandle"), (1, "dwMode")),
|
||||
)
|
||||
SetConsoleMode.errcheck = err_handler
|
||||
|
||||
for handle_id in [STDOUT_HANDLE, STDERR_HANDLE]:
|
||||
try:
|
||||
handle = GetStdHandle(handle_id)
|
||||
flags = GetConsoleMode(handle)
|
||||
SetConsoleMode(handle, flags | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
_win_color_fix()
|
||||
|
Loading…
x
Reference in New Issue
Block a user