Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SCons: Improve colored output #93479

Merged
merged 1 commit into from
Dec 17, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -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$

26 changes: 4 additions & 22 deletions SConstruct
Original file line number Diff line number Diff line change
@@ -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
@@ -630,7 +612,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)
@@ -1095,10 +1077,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,
)
)

47 changes: 18 additions & 29 deletions doc/tools/doc_status.py
Original file line number Diff line number Diff line change
@@ -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__)), "../../"))
Copy link
Member

@akien-mga akien-mga Dec 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is so messy :/

I know this was already used in make_rst.py but methods.py is a collection of methods for use by SCons to build the engine, it's not meant to be used by generic standalone scripts.

Those scripts shouldn't break if we move them around ideally.


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 @@
"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 @@ def generate_for_class(c: ET.Element):
table_column_names.append("Docs URL")
table_columns.append("url")

toggle_color(flags["c"])

################################################################################
# Help #
58 changes: 15 additions & 43 deletions doc/tools/make_rst.py
Original file line number Diff line number Diff line change
@@ -10,10 +10,10 @@
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 @@
]
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


Loading