Merge pull request #93479 from Repiteo/scons/better-colored-output

SCons: Improve colored output
This commit is contained in:
Rémi Verschelde 2024-12-17 16:18:41 +01:00
commit 182b4741ea
No known key found for this signature in database
GPG Key ID: C3336907360768E1
12 changed files with 150 additions and 255 deletions

View File

@ -98,7 +98,7 @@ repos:
name: doc-status
language: python
entry: python doc/tools/doc_status.py
args: [doc/classes, modules/*/doc_classes, platform/*/doc_classes]
args: [doc/classes, modules/*/doc_classes, platform/*/doc_classes, -c]
pass_filenames: false
files: ^(doc/classes|.*/doc_classes)/.*\.xml$

View File

@ -58,31 +58,13 @@ import gles3_builders
import glsl_builders
import methods
import scu_builders
from methods import print_error, print_warning
from methods import Ansi, print_error, print_info, print_warning
from platform_methods import architecture_aliases, architectures, compatibility_platform_aliases
if ARGUMENTS.get("target", "editor") == "editor":
_helper_module("editor.editor_builders", "editor/editor_builders.py")
_helper_module("editor.template_builders", "editor/template_builders.py")
# Enable ANSI escape code support on Windows 10 and later (for colored console output).
# <https://github.com/python/cpython/issues/73245>
if sys.stdout.isatty() and sys.platform == "win32":
try:
from ctypes import WinError, byref, windll # type: ignore
from ctypes.wintypes import DWORD # type: ignore
stdout_handle = windll.kernel32.GetStdHandle(DWORD(-11))
mode = DWORD(0)
if not windll.kernel32.GetConsoleMode(stdout_handle, byref(mode)):
raise WinError()
mode = DWORD(mode.value | 4)
if not windll.kernel32.SetConsoleMode(stdout_handle, mode):
raise WinError()
except Exception as e:
methods._colorize = False
print_error(f"Failed to enable ANSI escape code support, disabling color output.\n{e}")
# Scan possible build platforms
platform_list = [] # list of platforms
@ -635,7 +617,7 @@ detect.configure(env)
print(f'Building for platform "{env["platform"]}", architecture "{env["arch"]}", target "{env["target"]}".')
if env.dev_build:
print("NOTE: Developer build, with debug optimization level and debug symbols (unless overridden).")
print_info("Developer build, with debug optimization level and debug symbols (unless overridden).")
# Enforce our minimal compiler version requirements
cc_version = methods.get_compiler_version(env)
@ -1111,10 +1093,10 @@ def print_elapsed_time():
time_centiseconds = round((elapsed_time_sec % 1) * 100)
print(
"{}[Time elapsed: {}.{:02}]{}".format(
methods.ANSI.GRAY,
Ansi.GRAY,
time.strftime("%H:%M:%S", time.gmtime(elapsed_time_sec)),
time_centiseconds,
methods.ANSI.RESET,
Ansi.RESET,
)
)

View File

@ -3,18 +3,21 @@
import fnmatch
import math
import os
import platform
import re
import sys
import xml.etree.ElementTree as ET
from typing import Dict, List, Set
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../"))
from methods import COLOR_SUPPORTED, Ansi, toggle_color
################################################################################
# Config #
################################################################################
flags = {
"c": platform.platform() != "Windows", # Disable by default on windows, since we use ANSI escape codes
"c": COLOR_SUPPORTED,
"b": False,
"g": False,
"s": False,
@ -85,16 +88,16 @@ table_column_names = [
"Constructors",
]
colors = {
"name": [36], # cyan
"part_big_problem": [4, 31], # underline, red
"part_problem": [31], # red
"part_mostly_good": [33], # yellow
"part_good": [32], # green
"url": [4, 34], # underline, blue
"section": [1, 4], # bold, underline
"state_off": [36], # cyan
"state_on": [1, 35], # bold, magenta/plum
"bold": [1], # bold
"name": [Ansi.CYAN], # cyan
"part_big_problem": [Ansi.RED, Ansi.UNDERLINE], # underline, red
"part_problem": [Ansi.RED], # red
"part_mostly_good": [Ansi.YELLOW], # yellow
"part_good": [Ansi.GREEN], # green
"url": [Ansi.BLUE, Ansi.UNDERLINE], # underline, blue
"section": [Ansi.BOLD, Ansi.UNDERLINE], # bold, underline
"state_off": [Ansi.CYAN], # cyan
"state_on": [Ansi.BOLD, Ansi.MAGENTA], # bold, magenta/plum
"bold": [Ansi.BOLD], # bold
}
overall_progress_description_weight = 10
@ -111,13 +114,8 @@ def validate_tag(elem: ET.Element, tag: str) -> None:
def color(color: str, string: str) -> str:
if flags["c"] and terminal_supports_color():
color_format = ""
for code in colors[color]:
color_format += "\033[" + str(code) + "m"
return color_format + string + "\033[0m"
else:
return string
color_format = "".join([str(x) for x in colors[color]])
return f"{color_format}{string}{Ansi.RESET}"
ansi_escape = re.compile(r"\x1b[^m]*m")
@ -127,16 +125,6 @@ def nonescape_len(s: str) -> int:
return len(ansi_escape.sub("", s))
def terminal_supports_color():
p = sys.platform
supported_platform = p != "Pocket PC" and (p != "win32" or "ANSICON" in os.environ)
is_a_tty = hasattr(sys.stdout, "isatty") and sys.stdout.isatty()
if not supported_platform or not is_a_tty:
return False
return True
################################################################################
# Classes #
################################################################################
@ -342,6 +330,7 @@ if flags["u"]:
table_column_names.append("Docs URL")
table_columns.append("url")
toggle_color(flags["c"])
################################################################################
# Help #

View File

@ -10,10 +10,10 @@ import xml.etree.ElementTree as ET
from collections import OrderedDict
from typing import Any, Dict, List, Optional, TextIO, Tuple, Union
# Import hardcoded version information from version.py
root_directory = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../")
sys.path.append(root_directory) # Include the root directory
import version # noqa: E402
sys.path.insert(0, root_directory := os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../"))
import version
from methods import Ansi, toggle_color
# $DOCS_URL/path/to/page.html(#fragment-tag)
GODOT_DOCS_PATTERN = re.compile(r"^\$DOCS_URL/(.*)\.html(#.*)?$")
@ -90,8 +90,6 @@ BASE_STRINGS = [
]
strings_l10n: Dict[str, str] = {}
STYLES: Dict[str, str] = {}
CLASS_GROUPS: Dict[str, str] = {
"global": "Globals",
"node": "Nodes",
@ -699,31 +697,7 @@ def main() -> None:
)
args = parser.parse_args()
should_color = bool(args.color or sys.stdout.isatty() or os.environ.get("CI"))
# Enable ANSI escape code support on Windows 10 and later (for colored console output).
# <https://github.com/python/cpython/issues/73245>
if should_color and sys.stdout.isatty() and sys.platform == "win32":
try:
from ctypes import WinError, byref, windll # type: ignore
from ctypes.wintypes import DWORD # type: ignore
stdout_handle = windll.kernel32.GetStdHandle(DWORD(-11))
mode = DWORD(0)
if not windll.kernel32.GetConsoleMode(stdout_handle, byref(mode)):
raise WinError()
mode = DWORD(mode.value | 4)
if not windll.kernel32.SetConsoleMode(stdout_handle, mode):
raise WinError()
except Exception:
should_color = False
STYLES["red"] = "\x1b[91m" if should_color else ""
STYLES["green"] = "\x1b[92m" if should_color else ""
STYLES["yellow"] = "\x1b[93m" if should_color else ""
STYLES["bold"] = "\x1b[1m" if should_color else ""
STYLES["regular"] = "\x1b[22m" if should_color else ""
STYLES["reset"] = "\x1b[0m" if should_color else ""
toggle_color(args.color)
# Retrieve heading translations for the given language.
if not args.dry_run and args.lang != "en":
@ -834,16 +808,16 @@ def main() -> None:
if state.script_language_parity_check.hit_count > 0:
if not args.verbose:
print(
f'{STYLES["yellow"]}{state.script_language_parity_check.hit_count} code samples failed parity check. Use --verbose to get more information.{STYLES["reset"]}'
f"{Ansi.YELLOW}{state.script_language_parity_check.hit_count} code samples failed parity check. Use --verbose to get more information.{Ansi.RESET}"
)
else:
print(
f'{STYLES["yellow"]}{state.script_language_parity_check.hit_count} code samples failed parity check:{STYLES["reset"]}'
f"{Ansi.YELLOW}{state.script_language_parity_check.hit_count} code samples failed parity check:{Ansi.RESET}"
)
for class_name in state.script_language_parity_check.hit_map.keys():
class_hits = state.script_language_parity_check.hit_map[class_name]
print(f'{STYLES["yellow"]}- {len(class_hits)} hits in class "{class_name}"{STYLES["reset"]}')
print(f'{Ansi.YELLOW}- {len(class_hits)} hits in class "{class_name}"{Ansi.RESET}')
for context, error in class_hits:
print(f" - {error} in {format_context_name(context)}")
@ -853,24 +827,22 @@ def main() -> None:
if state.num_warnings >= 2:
print(
f'{STYLES["yellow"]}{state.num_warnings} warnings were found in the class reference XML. Please check the messages above.{STYLES["reset"]}'
f"{Ansi.YELLOW}{state.num_warnings} warnings were found in the class reference XML. Please check the messages above.{Ansi.RESET}"
)
elif state.num_warnings == 1:
print(
f'{STYLES["yellow"]}1 warning was found in the class reference XML. Please check the messages above.{STYLES["reset"]}'
f"{Ansi.YELLOW}1 warning was found in the class reference XML. Please check the messages above.{Ansi.RESET}"
)
if state.num_errors >= 2:
print(
f'{STYLES["red"]}{state.num_errors} errors were found in the class reference XML. Please check the messages above.{STYLES["reset"]}'
f"{Ansi.RED}{state.num_errors} errors were found in the class reference XML. Please check the messages above.{Ansi.RESET}"
)
elif state.num_errors == 1:
print(
f'{STYLES["red"]}1 error was found in the class reference XML. Please check the messages above.{STYLES["reset"]}'
)
print(f"{Ansi.RED}1 error was found in the class reference XML. Please check the messages above.{Ansi.RESET}")
if state.num_warnings == 0 and state.num_errors == 0:
print(f'{STYLES["green"]}No warnings or errors found in the class reference XML.{STYLES["reset"]}')
print(f"{Ansi.GREEN}No warnings or errors found in the class reference XML.{Ansi.RESET}")
if not args.dry_run:
print(f"Wrote reStructuredText files for each class to: {args.output}")
else:
@ -881,12 +853,12 @@ def main() -> None:
def print_error(error: str, state: State) -> None:
print(f'{STYLES["red"]}{STYLES["bold"]}ERROR:{STYLES["regular"]} {error}{STYLES["reset"]}')
print(f"{Ansi.RED}{Ansi.BOLD}ERROR:{Ansi.REGULAR} {error}{Ansi.RESET}")
state.num_errors += 1
def print_warning(warning: str, state: State) -> None:
print(f'{STYLES["yellow"]}{STYLES["bold"]}WARNING:{STYLES["regular"]} {warning}{STYLES["reset"]}')
print(f"{Ansi.YELLOW}{Ansi.BOLD}WARNING:{Ansi.REGULAR} {warning}{Ansi.RESET}")
state.num_warnings += 1

View File

@ -10,26 +10,63 @@ from collections import OrderedDict
from enum import Enum
from io import StringIO, TextIOWrapper
from pathlib import Path
from typing import Generator, List, Optional, Union, cast
from typing import Final, Generator, List, Optional, Union, cast
# Get the "Godot" folder name ahead of time
base_folder_path = str(os.path.abspath(Path(__file__).parent)) + "/"
base_folder_only = os.path.basename(os.path.normpath(base_folder_path))
# Listing all the folders we have converted
# for SCU in scu_builders.py
_scu_folders = set()
################################################################################
# COLORIZE
################################################################################
IS_CI: Final[bool] = bool(os.environ.get("CI"))
IS_TTY: Final[bool] = bool(sys.stdout.isatty())
def _color_supported() -> bool:
"""
Enables ANSI escape code support on Windows 10 and later (for colored console output).
See here: https://github.com/python/cpython/issues/73245
"""
if sys.platform == "win32" and IS_TTY:
try:
from ctypes import WinError, byref, windll # type: ignore
from ctypes.wintypes import DWORD # type: ignore
stdout_handle = windll.kernel32.GetStdHandle(DWORD(-11))
mode = DWORD(0)
if not windll.kernel32.GetConsoleMode(stdout_handle, byref(mode)):
raise WinError()
mode = DWORD(mode.value | 4)
if not windll.kernel32.SetConsoleMode(stdout_handle, mode):
raise WinError()
except (TypeError, OSError) as e:
print(f"Failed to enable ANSI escape code support, disabling color output.\n{e}", file=sys.stderr)
return False
return IS_TTY or IS_CI
# Colors are disabled in non-TTY environments such as pipes. This means
# that if output is redirected to a file, it won't contain color codes.
# Colors are always enabled on continuous integration.
_colorize = bool(sys.stdout.isatty() or os.environ.get("CI"))
COLOR_SUPPORTED: Final[bool] = _color_supported()
_can_color: bool = COLOR_SUPPORTED
def set_scu_folders(scu_folders):
global _scu_folders
_scu_folders = scu_folders
def toggle_color(value: Optional[bool] = None) -> None:
"""
Explicitly toggle color codes, regardless of support.
- `value`: An optional boolean to explicitly set the color
state instead of toggling.
"""
global _can_color
_can_color = value if value is not None else not _can_color
class ANSI(Enum):
class Ansi(Enum):
"""
Enum class for adding ansi colorcodes directly into strings.
Automatically converts values to strings representing their
@ -39,6 +76,7 @@ class ANSI(Enum):
RESET = "\x1b[0m"
BOLD = "\x1b[1m"
DIM = "\x1b[2m"
ITALIC = "\x1b[3m"
UNDERLINE = "\x1b[4m"
STRIKETHROUGH = "\x1b[9m"
@ -53,24 +91,49 @@ class ANSI(Enum):
CYAN = "\x1b[36m"
WHITE = "\x1b[37m"
PURPLE = "\x1b[38;5;93m"
PINK = "\x1b[38;5;206m"
ORANGE = "\x1b[38;5;214m"
GRAY = "\x1b[38;5;244m"
LIGHT_BLACK = "\x1b[90m"
LIGHT_RED = "\x1b[91m"
LIGHT_GREEN = "\x1b[92m"
LIGHT_YELLOW = "\x1b[93m"
LIGHT_BLUE = "\x1b[94m"
LIGHT_MAGENTA = "\x1b[95m"
LIGHT_CYAN = "\x1b[96m"
LIGHT_WHITE = "\x1b[97m"
GRAY = LIGHT_BLACK if IS_CI else BLACK
"""
Special case. GitHub Actions doesn't convert `BLACK` to gray as expected, but does convert `LIGHT_BLACK`.
By implementing `GRAY`, we handle both cases dynamically, while still allowing for explicit values if desired.
"""
def __str__(self) -> str:
global _colorize
return str(self.value) if _colorize else ""
global _can_color
return str(self.value) if _can_color else ""
def print_info(*values: object) -> None:
"""Prints a informational message with formatting."""
print(f"{Ansi.GRAY}{Ansi.BOLD}INFO:{Ansi.REGULAR}", *values, Ansi.RESET)
def print_warning(*values: object) -> None:
"""Prints a warning message with formatting."""
print(f"{ANSI.YELLOW}{ANSI.BOLD}WARNING:{ANSI.REGULAR}", *values, ANSI.RESET, file=sys.stderr)
print(f"{Ansi.YELLOW}{Ansi.BOLD}WARNING:{Ansi.REGULAR}", *values, Ansi.RESET, file=sys.stderr)
def print_error(*values: object) -> None:
"""Prints an error message with formatting."""
print(f"{ANSI.RED}{ANSI.BOLD}ERROR:{ANSI.REGULAR}", *values, ANSI.RESET, file=sys.stderr)
print(f"{Ansi.RED}{Ansi.BOLD}ERROR:{Ansi.REGULAR}", *values, Ansi.RESET, file=sys.stderr)
# Listing all the folders we have converted
# for SCU in scu_builders.py
_scu_folders = set()
def set_scu_folders(scu_folders):
global _scu_folders
_scu_folders = scu_folders
def add_source_files_orig(self, sources, files, allow_gen=False):
@ -164,7 +227,7 @@ def get_version_info(module_version_string="", silent=False):
if os.getenv("BUILD_NAME") is not None:
build_name = str(os.getenv("BUILD_NAME"))
if not silent:
print(f"Using custom build name: '{build_name}'.")
print_info(f"Using custom build name: '{build_name}'.")
import version
@ -186,7 +249,7 @@ def get_version_info(module_version_string="", silent=False):
if os.getenv("GODOT_VERSION_STATUS") is not None:
version_info["status"] = str(os.getenv("GODOT_VERSION_STATUS"))
if not silent:
print(f"Using version status '{version_info['status']}', overriding the original '{version.status}'.")
print_info(f"Using version status '{version_info['status']}', overriding the original '{version.status}'.")
# Parse Git hash if we're in a Git repo.
githash = ""
@ -442,7 +505,7 @@ def use_windows_spawn_fix(self, platform=None):
def no_verbose(env):
colors = [ANSI.BLUE, ANSI.BOLD, ANSI.REGULAR, ANSI.RESET]
colors = [Ansi.BLUE, Ansi.BOLD, Ansi.REGULAR, Ansi.RESET]
# There is a space before "..." to ensure that source file names can be
# Ctrl + clicked in the VS Code terminal.
@ -797,7 +860,7 @@ def show_progress(env):
# Progress reporting is not available in non-TTY environments since it messes with the output
# (for example, when writing to a file). Ninja has its own progress/tracking tool that clashes
# with ours.
if not env["progress"] or not sys.stdout.isatty() or env["ninja"]:
if not env["progress"] or not IS_TTY or env["ninja"]:
return
NODE_COUNT_FILENAME = f"{base_folder_path}.scons_node_count"
@ -1485,7 +1548,7 @@ def generate_copyright_header(filename: str) -> str:
"""
filename = filename.split("/")[-1].ljust(MARGIN)
if len(filename) > MARGIN:
print(f'WARNING: Filename "{filename}" too large for copyright header.')
print_warning(f'Filename "{filename}" too large for copyright header.')
return TEMPLATE % filename

21
misc/scripts/install_d3d12_sdk_windows.py Executable file → Normal file
View File

@ -6,16 +6,9 @@ import subprocess
import sys
import urllib.request
# Enable ANSI escape code support on Windows 10 and later (for colored console output).
# <https://github.com/python/cpython/issues/73245>
if sys.platform == "win32":
from ctypes import byref, c_int, windll
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../"))
stdout_handle = windll.kernel32.GetStdHandle(c_int(-11))
mode = c_int(0)
windll.kernel32.GetConsoleMode(c_int(stdout_handle), byref(mode))
mode = c_int(mode.value | 4)
windll.kernel32.SetConsoleMode(c_int(stdout_handle), mode)
from methods import Ansi
# Base Godot dependencies path
# If cross-compiling (no LOCALAPPDATA), we install in `bin`
@ -49,7 +42,7 @@ if not os.path.exists(deps_folder):
os.makedirs(deps_folder)
# Mesa NIR
print("\x1b[1m[1/3] Mesa NIR\x1b[0m")
print(f"{Ansi.BOLD}[1/3] Mesa NIR{Ansi.RESET}")
if os.path.isfile(mesa_archive):
os.remove(mesa_archive)
print(f"Downloading Mesa NIR {mesa_filename} ...")
@ -76,7 +69,7 @@ if dlltool == "":
dlltool = shutil.which("x86_64-w64-mingw32-dlltool") or ""
has_mingw = gendef != "" and dlltool != ""
print("\x1b[1m[2/3] WinPixEventRuntime\x1b[0m")
print(f"{Ansi.BOLD}[2/3] WinPixEventRuntime{Ansi.RESET}")
if os.path.isfile(pix_archive):
os.remove(pix_archive)
print(f"Downloading WinPixEventRuntime {pix_version} ...")
@ -107,7 +100,7 @@ else:
print(f"WinPixEventRuntime {pix_version} installed successfully.\n")
# DirectX 12 Agility SDK
print("\x1b[1m[3/3] DirectX 12 Agility SDK\x1b[0m")
print(f"{Ansi.BOLD}[3/3] DirectX 12 Agility SDK{Ansi.RESET}")
if os.path.isfile(agility_sdk_archive):
os.remove(agility_sdk_archive)
print(f"Downloading DirectX 12 Agility SDK {agility_sdk_version} ...")
@ -123,5 +116,5 @@ os.remove(agility_sdk_archive)
print(f"DirectX 12 Agility SDK {agility_sdk_version} installed successfully.\n")
# Complete message
print(f'\x1b[92mAll Direct3D 12 SDK components were installed to "{deps_folder}" successfully!\x1b[0m')
print('\x1b[92mYou can now build Godot with Direct3D 12 support enabled by running "scons d3d12=yes".\x1b[0m')
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}')

View File

@ -1,29 +1,13 @@
#!/usr/bin/env python
from misc.utility.scons_hints import *
import atexit
import sys
import time
from typing import TYPE_CHECKING
import methods
# Enable ANSI escape code support on Windows 10 and later (for colored console output).
# <https://github.com/python/cpython/issues/73245>
if sys.stdout.isatty() and sys.platform == "win32":
try:
from ctypes import WinError, byref, windll # type: ignore
from ctypes.wintypes import DWORD # type: ignore
stdout_handle = windll.kernel32.GetStdHandle(DWORD(-11))
mode = DWORD(0)
if not windll.kernel32.GetConsoleMode(stdout_handle, byref(mode)):
raise WinError()
mode = DWORD(mode.value | 4)
if not windll.kernel32.SetConsoleMode(stdout_handle, mode):
raise WinError()
except Exception as e:
methods._colorize = False
methods.print_error(f"Failed to enable ANSI escape code support, disabling color output.\n{e}")
if TYPE_CHECKING:
from misc.utility.scons_hints import *
# For the reference:
# - CCFLAGS are compilation flags shared between C and C++
@ -793,10 +777,10 @@ def print_elapsed_time():
time_centiseconds = round((elapsed_time_sec % 1) * 100)
print(
"{}[Time elapsed: {}.{:02}]{}".format(
methods.ANSI.GRAY,
methods.Ansi.GRAY,
time.strftime("%H:%M:%S", time.gmtime(elapsed_time_sec)),
time_centiseconds,
methods.ANSI.RESET,
methods.Ansi.RESET,
)
)

View File

@ -1,49 +1,13 @@
import os
import sys
from enum import Enum
# Colors are disabled in non-TTY environments such as pipes. This means
# that if output is redirected to a file, it won't contain color codes.
# Colors are always enabled on continuous integration.
_colorize = bool(sys.stdout.isatty() or os.environ.get("CI"))
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../../"))
class ANSI(Enum):
"""
Enum class for adding ansi colorcodes directly into strings.
Automatically converts values to strings representing their
internal value, or an empty string in a non-colorized scope.
"""
RESET = "\x1b[0m"
BOLD = "\x1b[1m"
ITALIC = "\x1b[3m"
UNDERLINE = "\x1b[4m"
STRIKETHROUGH = "\x1b[9m"
REGULAR = "\x1b[22;23;24;29m"
BLACK = "\x1b[30m"
RED = "\x1b[31m"
GREEN = "\x1b[32m"
YELLOW = "\x1b[33m"
BLUE = "\x1b[34m"
MAGENTA = "\x1b[35m"
CYAN = "\x1b[36m"
WHITE = "\x1b[37m"
PURPLE = "\x1b[38;5;93m"
PINK = "\x1b[38;5;206m"
ORANGE = "\x1b[38;5;214m"
GRAY = "\x1b[38;5;244m"
def __str__(self) -> str:
global _colorize
return str(self.value) if _colorize else ""
from methods import Ansi
def no_verbose(env):
colors = [ANSI.BLUE, ANSI.BOLD, ANSI.REGULAR, ANSI.RESET]
colors = [Ansi.BLUE, Ansi.BOLD, Ansi.REGULAR, Ansi.RESET]
# There is a space before "..." to ensure that source file names can be
# Ctrl + clicked in the VS Code terminal.

View File

@ -1,29 +1,13 @@
#!/usr/bin/env python
from misc.utility.scons_hints import *
import atexit
import sys
import time
from typing import TYPE_CHECKING
import methods
# Enable ANSI escape code support on Windows 10 and later (for colored console output).
# <https://github.com/python/cpython/issues/73245>
if sys.stdout.isatty() and sys.platform == "win32":
try:
from ctypes import WinError, byref, windll # type: ignore
from ctypes.wintypes import DWORD # type: ignore
stdout_handle = windll.kernel32.GetStdHandle(DWORD(-11))
mode = DWORD(0)
if not windll.kernel32.GetConsoleMode(stdout_handle, byref(mode)):
raise WinError()
mode = DWORD(mode.value | 4)
if not windll.kernel32.SetConsoleMode(stdout_handle, mode):
raise WinError()
except Exception as e:
methods._colorize = False
methods.print_error(f"Failed to enable ANSI escape code support, disabling color output.\n{e}")
if TYPE_CHECKING:
from misc.utility.scons_hints import *
# For the reference:
# - CCFLAGS are compilation flags shared between C and C++
@ -335,10 +319,10 @@ def print_elapsed_time():
time_centiseconds = round((elapsed_time_sec % 1) * 100)
print(
"{}[Time elapsed: {}.{:02}]{}".format(
methods.ANSI.GRAY,
methods.Ansi.GRAY,
time.strftime("%H:%M:%S", time.gmtime(elapsed_time_sec)),
time_centiseconds,
methods.ANSI.RESET,
methods.Ansi.RESET,
)
)

View File

@ -1,49 +1,13 @@
import os
import sys
from enum import Enum
# Colors are disabled in non-TTY environments such as pipes. This means
# that if output is redirected to a file, it won't contain color codes.
# Colors are always enabled on continuous integration.
_colorize = bool(sys.stdout.isatty() or os.environ.get("CI"))
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../../"))
class ANSI(Enum):
"""
Enum class for adding ansi colorcodes directly into strings.
Automatically converts values to strings representing their
internal value, or an empty string in a non-colorized scope.
"""
RESET = "\x1b[0m"
BOLD = "\x1b[1m"
ITALIC = "\x1b[3m"
UNDERLINE = "\x1b[4m"
STRIKETHROUGH = "\x1b[9m"
REGULAR = "\x1b[22;23;24;29m"
BLACK = "\x1b[30m"
RED = "\x1b[31m"
GREEN = "\x1b[32m"
YELLOW = "\x1b[33m"
BLUE = "\x1b[34m"
MAGENTA = "\x1b[35m"
CYAN = "\x1b[36m"
WHITE = "\x1b[37m"
PURPLE = "\x1b[38;5;93m"
PINK = "\x1b[38;5;206m"
ORANGE = "\x1b[38;5;214m"
GRAY = "\x1b[38;5;244m"
def __str__(self) -> str:
global _colorize
return str(self.value) if _colorize else ""
from methods import Ansi
def no_verbose(env):
colors = [ANSI.BLUE, ANSI.BOLD, ANSI.REGULAR, ANSI.RESET]
colors = [Ansi.BLUE, Ansi.BOLD, Ansi.REGULAR, Ansi.RESET]
# There is a space before "..." to ensure that source file names can be
# Ctrl + clicked in the VS Code terminal.

View File

@ -3,7 +3,7 @@ import platform
import sys
from typing import TYPE_CHECKING
from methods import get_compiler_version, print_error, print_warning, using_gcc
from methods import get_compiler_version, print_error, print_info, print_warning, using_gcc
from platform_methods import detect_arch, validate_arch
if TYPE_CHECKING:
@ -492,7 +492,7 @@ def configure(env: "SConsEnvironment"):
else:
# The default crash handler depends on glibc, so if the host uses
# a different libc (BSD libc, musl), libexecinfo is required.
print("Note: Using `execinfo=no` disables the crash handler on platforms where glibc is missing.")
print_info("Using `execinfo=no` disables the crash handler on platforms where glibc is missing.")
else:
env.Append(CPPDEFINES=["CRASH_HANDLER_ENABLED"])

View File

@ -13,7 +13,7 @@ from emscripten_helpers import (
)
from SCons.Util import WhereIs
from methods import get_compiler_version, print_error, print_warning
from methods import get_compiler_version, print_error, print_info, print_warning
from platform_methods import validate_arch
if TYPE_CHECKING:
@ -107,7 +107,7 @@ def configure(env: "SConsEnvironment"):
env.Append(LINKFLAGS=["-sASSERTIONS=1"])
if env.editor_build and env["initial_memory"] < 64:
print("Note: Forcing `initial_memory=64` as it is required for the web editor.")
print_info("Forcing `initial_memory=64` as it is required for the web editor.")
env["initial_memory"] = 64
env.Append(LINKFLAGS=["-sINITIAL_MEMORY=%sMB" % env["initial_memory"]])