From 114a4d2951ff049b133680fe7da66b8a26a7f1d0 Mon Sep 17 00:00:00 2001 From: Lightmann Date: Mon, 8 Jan 2024 18:31:04 -0500 Subject: [PATCH] Create shared dbprint utils --- setup.py | 3 +- src/dragon/device.py | 65 +++++++++++++++++-------------------- src/dragon/editor.py | 27 ++++++--------- src/dragon/util.py | 64 +----------------------------------- src/dragongen/bfilter.py | 18 ++-------- src/dragongen/control.py | 34 ++++++------------- src/dragongen/generation.py | 39 +++++++++++----------- src/dragongen/util.py | 20 +----------- src/shared/util.py | 30 +++++++++++++++++ 9 files changed, 105 insertions(+), 195 deletions(-) create mode 100644 src/shared/util.py diff --git a/setup.py b/setup.py index a0499d47d..60eeba11c 100644 --- a/setup.py +++ b/setup.py @@ -8,11 +8,12 @@ author='cynder', url='https://dragon.cynder.me/', install_requires=['ninja', 'pyyaml', 'ruyaml', 'packaging', 'tqdm'], - packages=['dragon', 'dragongen', 'buildgen'], + packages=['dragon', 'dragongen', 'buildgen', 'shared'], package_dir={ 'dragon': 'src/dragon', 'dragongen': 'src/dragongen', 'buildgen': 'src/buildgen', + 'shared': 'src/shared', }, package_data={ 'dragon': ['shscripts/*', 'config/*'], diff --git a/src/dragon/device.py b/src/dragon/device.py index 7055f6dcc..154fe5e65 100644 --- a/src/dragon/device.py +++ b/src/dragon/device.py @@ -13,14 +13,7 @@ ''' import os, sys, yaml, subprocess, socket -from .util import dprintline, OutputColors, OutputWeight - -dbstate = lambda msg: dprintline(label_color=OutputColors.Green, tool_name="Device", text_color=OutputColors.White, - text_weight=OutputWeight.Bold, pusher=False, msg=msg) -dbwarn = lambda msg: dprintline(label_color=OutputColors.Yellow, tool_name="Device", text_color=OutputColors.White, - text_weight=OutputWeight.Normal, pusher=False, msg=msg) -dberror = lambda msg: dprintline(label_color=OutputColors.Red, tool_name="Device", text_color=OutputColors.White, - text_weight=OutputWeight.Bold, pusher=False, msg=msg) +from shared.util import dbstate, dbwarn, dberror def system(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE): @@ -116,18 +109,18 @@ def run_cmd(self, cmd, quiet=False): return if not self.test_connection(): - dberror(f'Could not connect to device at {self.host}:{self.port}') + dberror("Device", f'Could not connect to device at {self.host}:{self.port}') if self.host == "localhost" and self.port == 4444: - dberror(f'To configure a new device, run "dragon s"') + dberror("Device", f'To configure a new device, run "dragon s"') self.connection_failure_resolver() return if not quiet: if cmd == '': - dbstate("Launching Device Shell") + dbstate("Device", "Launching Device Shell") DeviceShell.launch(self) return - dbstate(f'Running "{cmd}" on {self.host}:{self.port}') + dbstate("Device", f'Running "{cmd}" on {self.host}:{self.port}') return system_pipe_output(f'ssh -p {self.port} root@{self.host} "{cmd}"') def export_ip(self): @@ -139,20 +132,20 @@ def export_ip(self): print(f'export {x}="{exports[x]}"') def setup_key_auth(self): - dbstate('Setting up keybased auth') + dbstate("Device", 'Setting up keybased auth') exists = system('stat ~/.ssh/id_rsa') == 0 if not exists: - dbstate('Generating Keyfile') + dbstate("Device", 'Generating Keyfile') system("ssh-keygen -q -t rsa -N '' -f ~/.ssh/id_rsa <<&1 >/dev/null") # We don't use ssh-copy-id because some systems (Elucubratus, etc) don't have it - dbstate('Copying keyfile') + dbstate("Device", 'Copying keyfile') success = system( f'cat ~/.ssh/id_rsa.pub | ssh -p {self.port} root@{self.host} "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"') if success == 0: - dbstate('Enabled keybased auth') + dbstate("Device", 'Enabled keybased auth') else: - dberror('Failed') + dberror("Device", 'Failed') class DeviceManager(object): @@ -188,10 +181,10 @@ def resolve_known_hosts_issue(self, stderr): known_hosts_line = int(line.split('known_hosts:')[-1]) file_location = line.split(' key in ')[-1].split(":")[0] - dbwarn("There is already an entry in the known_hosts file for your system") + dbwarn("Device", "There is already an entry in the known_hosts file for your system") if file_location: - dbwarn(f'Bad entry: {file_location}:{known_hosts_line}') - dbwarn("You will not be able to connect to this device until this is resolved. Remove this line? (y/n)") + dbwarn("Device", f'Bad entry: {file_location}:{known_hosts_line}') + dbwarn("Device", "You will not be able to connect to this device until this is resolved. Remove this line? (y/n)") if 'y' in input('> ').lower(): try: with open(file_location, "r") as infile: @@ -206,13 +199,13 @@ def resolve_known_hosts_issue(self, stderr): print(f'Removed {line}') return True except IOError: - dberror("Error reading or writing to file. Please manually remove the line.") + dberror("Device", "Error reading or writing to file. Please manually remove the line.") return False except Exception: - dberror("Unknown error occured.") + dberror("Device", "Unknown error occured.") return False - dberror("Could not automatically resolve any information about the error. Please See the following output.") + dberror("Device", "Could not automatically resolve any information about the error. Please See the following output.") print(stderr) return False @@ -225,9 +218,9 @@ def setup(self): ''' - dbstate('Enter Device IP or hostname') + dbstate("Device", 'Enter Device IP or hostname') ip = input('>>> ') - dbstate('enter port (leave empty for 22)') + dbstate("Device", 'enter port (leave empty for 22)') port = input('>>> ') if port == '': @@ -237,13 +230,13 @@ def setup(self): device = Device(ip, port) - dbstate('Testing Connection') + dbstate("Device", 'Testing Connection') connected = False if device.test_connection(): - dbstate('Connected!') + dbstate("Device", 'Connected!') connected = True else: - dbwarn('Connection failed, add it anyways? (y/n)') + dbwarn("Device", 'Connection failed, add it anyways? (y/n)') if 'y' not in input('> ').lower(): return @@ -258,14 +251,14 @@ def setup(self): if success: break if success: - dbstate("Successfully resolved issue") + dbstate("Device", "Successfully resolved issue") else: - dberror("Could not resolve known_hosts issue.") + dberror("Device", "Could not resolve known_hosts issue.") if not device.test_keybased_auth(): device.setup_key_auth() else: - dbstate("Keybased auth already configured") + dbstate("Device", "Keybased auth already configured") self.add_device(device) @@ -278,7 +271,7 @@ def main(): device_manager.setup() except KeyboardInterrupt: print() - dbstate('Cancelled') + dbstate("Device", 'Cancelled') if 'run' in sys.argv[1]: device_manager.current.run_cmd(' '.join(sys.argv[2:])) if 'qr' in sys.argv[1]: @@ -286,13 +279,13 @@ def main(): if 'get' in sys.argv[1]: device_manager.current.export_ip() if 'test' in sys.argv[1]: - dbstate('Testing Connection') + dbstate("Device", 'Testing Connection') if device_manager.current.test_connection(): - dbstate('Connected!') + dbstate("Device", 'Connected!') exit(0) else: - dberror('Connection to device failed') - dberror('Make sure SSH is functioning properly and/or run "dragon s" to configure your device') + dberror("Device", 'Connection to device failed') + dberror("Device", 'Make sure SSH is functioning properly and/or run "dragon s" to configure your device') exit(1) diff --git a/src/dragon/editor.py b/src/dragon/editor.py index 5216a0c81..dd751d578 100644 --- a/src/dragon/editor.py +++ b/src/dragon/editor.py @@ -7,26 +7,19 @@ # if you're here to contribute to this file, im sorry. ::::) -import os, sys, pwd, pprint +import os, sys, pwd import ruyaml as yaml -from .util import dprintline, OutputColors, OutputWeight - -dbstate = lambda msg: dprintline(label_color=OutputColors.Green, tool_name="Project Editor", - text_color=OutputColors.White, text_weight=OutputWeight.Bold, pusher=False, msg=msg) -dbwarn = lambda msg: dprintline(label_color=OutputColors.Yellow, tool_name="Project Editor", - text_color=OutputColors.White, text_weight=OutputWeight.Normal, pusher=False, msg=msg) -dberror = lambda msg: dprintline(label_color=OutputColors.Red, tool_name="Project Editor", - text_color=OutputColors.White, text_weight=OutputWeight.Bold, pusher=False, msg=msg) +from shared.util import dbstate def get_input(prompt, default): - dbstate(f'{prompt} ({default})') + dbstate("Project Editor", f'{prompt} ({default})') ret = input('>> ') return ret if ret.strip() else default def get_from_selector(prompt, values, default): - dbstate(prompt) + dbstate("Project Editor", prompt) itemlist = [] for i, key in enumerate(values): print(f'[{i}] > {key}') @@ -430,9 +423,9 @@ def __init__(self, root_directory): self.variables = {} def create_new(self): - dbstate('-=-=============================') - dbstate('Creating new Package') - dbstate('-=-=============================') + dbstate("Project Editor", '-=-=============================') + dbstate("Project Editor", 'Creating new Package') + dbstate("Project Editor", '-=-=============================') self.variables['name'] = get_input('Project Name', self.directory_name) self.variables['id'] = get_input('Bundle ID', f'com.{self.current_username}.{self.directory_name}') self.variables['depends'] = 'mobilesubstrate' @@ -455,9 +448,9 @@ def __init__(self, variables=None): self.name = '' def create_new(self, proj_root): - dbstate('-=-=============================') - dbstate('Creating new Module') - dbstate('-=-=============================') + dbstate("Project Editor", '-=-=============================') + dbstate("Project Editor", 'Creating new Module') + dbstate("Project Editor", '-=-=============================') self.variables['type'] = get_from_selector('Select Module Type', {'Tweak': 'tweak', 'App': 'app', 'CLI Tool': 'cli', 'Library': 'library', 'Preference Bundle': 'prefs', diff --git a/src/dragon/util.py b/src/dragon/util.py index cfe23a049..faaf88c27 100644 --- a/src/dragon/util.py +++ b/src/dragon/util.py @@ -1,15 +1,11 @@ #!/usr/bin/env python3 import os.path as path -from enum import IntEnum import pkg_resources -import sys - -DRAGONBUILD_VERSION = pkg_resources.get_distribution('dragon').version def version() -> str: - return DRAGONBUILD_VERSION + return pkg_resources.get_distribution('dragon').version def tool_path() -> str: @@ -18,61 +14,3 @@ def tool_path() -> str: def deployable_path() -> str: return path.dirname(__file__) + '/config/' - - -colors = [["\033[0;31m", "\033[0;32m", "\033[0;33m", "\033[0;34m", "\033[0;36m", - "\033[0;37m", "\033[0m"], ["\033[1;31m", "\033[1;32m", "\033[1;33m", "\033[1;34m", - "\033[1;36m", "\033[1;37m", "\033[0m"]] - - -class OutputColors(IntEnum): - Black = 30 - Red = 31 - Green = 32 - Yellow = 33 - Blue = 34 - Magenta = 35 - Cyan = 36 - White = 37 - - -class OutputWeight(IntEnum): - Normal = 0 - Bold = 1 - - -def color_string(output_color, output_weight): - return f'\033[{str(output_weight.value)};{str(output_color.value)}m' - - -def dprintline(label_color: OutputColors, tool_name: str, text_color: OutputColors, text_weight: OutputWeight, - pusher: bool, msg: str): - print("%s[%s]%s %s%s%s" % ( - color_string(label_color, OutputWeight.Bold), tool_name, color_string(text_color, text_weight), - ">>> " if pusher else "", msg, colors[0][6])) - - -class ShellHarnessAdapter: - def __init__(self): - pass - - @staticmethod - def echo(string): - print(f'echo -e "{string}"', file=sys.stdout) - - @staticmethod - def printline(label_color: OutputColors, tool_name: str, text_color: OutputColors, text_weight: OutputWeight, - pusher: bool, msg: str): - output_string = "%s[%s]%s %s%s%s" % ( - color_string(label_color, OutputWeight.Bold), tool_name, color_string(text_color, text_weight), - ">>> " if pusher else "", msg, colors[0][6]) - ShellHarnessAdapter.echo(output_string) - - def dprintline(col: int, tool: str, textcol: int, bold: int, pusher: int, msg: str): - ShellHarnessAdapter.echo("%s[%s]%s %s%s%s" % ( - colors[1][col], tool, colors[bold][textcol], ">>> " if pusher - else "", msg, colors[0][6])) - - @staticmethod - def run(cmd: str): - print(f'{cmd}') diff --git a/src/dragongen/bfilter.py b/src/dragongen/bfilter.py index a4cf6c17a..0bfa98c8b 100644 --- a/src/dragongen/bfilter.py +++ b/src/dragongen/bfilter.py @@ -1,21 +1,7 @@ #!/usr/bin/env python3 import yaml, os, sys - -colors = [["\033[0;31m", "\033[0;32m", "\033[0;33m", "\033[0;34m", "\033[0;36m", - "\033[0;37m", "\033[0m"], ["\033[1;31m", "\033[1;32m", "\033[1;33m", "\033[1;34m", - "\033[1;36m", "\033[1;37m", "\033[0m"]] - - -def dprintline(col: int, tool: str, textcol: int, bold: int, pusher: int, msg: str): - print("%s[%s]%s %s%s%s" % ( - colors[1][col], tool, colors[bold][textcol], ">>> " if pusher else "", msg, colors[0][6])) - - -dbstate = lambda msg: dprintline(1, "Packager", 5, 1, 0, msg) -dbwarn = lambda msg: dprintline(2, "Packager", 5, 0, 0, msg) -dberror = lambda msg: dprintline(0, "Packager", 5, 1, 0, msg) - +# from shared.util import dbstate # This script will get called w/ # argc=3 argv[0] argv[1] argv[2] @@ -26,7 +12,7 @@ def main(): with open(sys.argv[1]) as f: config = yaml.safe_load(f) - # dbstate("Creating Filter for " + sys.argv[2]) + # dbstate("Packager", "Creating Filter for " + sys.argv[2]) filter_dict = config[sys.argv[2]]['filter'] print(filter_serialize(filter_dict)) diff --git a/src/dragongen/control.py b/src/dragongen/control.py index d12c1feab..35851e4ad 100644 --- a/src/dragongen/control.py +++ b/src/dragongen/control.py @@ -1,27 +1,13 @@ #!/usr/bin/env python3 import yaml, os, sys - -colors = [["\033[0;31m", "\033[0;32m", "\033[0;33m", "\033[0;34m", "\033[0;36m", - "\033[0;37m", "\033[0m"], ["\033[1;31m", "\033[1;32m", "\033[1;33m", "\033[1;34m", - "\033[1;36m", "\033[1;37m", "\033[0m"]] - - -def dprintline(col: int, tool: str, textcol: int, bold: int, pusher: int, msg: str): - print("%s[%s]%s %s%s%s" % ( - colors[1][col], tool, colors[bold][textcol], ">>> " if pusher else "", msg, colors[0][6])) - - -dbstate = lambda msg: dprintline(1, "Packager", 5, 1, 0, msg) -dbwarn = lambda msg: dprintline(2, "Packager", 5, 0, 0, msg) -dberror = lambda msg: dprintline(0, "Packager", 5, 1, 0, msg) - +from shared.util import dbstate, dbwarn, dberror # This script will get called w/ # argc=3 argv[0] argv[1] argv[2] # python3 $DRAGON_ROOT_DIR/internal/control.py DragonMake ./$DRAGON_DIR/_/DEBIAN/control def main(): - dbstate("Pulling 'control' values from DragonMake") + dbstate("Packager", "Pulling 'control' values from DragonMake") keys = { 'name': 'Name', @@ -67,9 +53,9 @@ def main(): config = yaml.safe_load(f) else: - dberror('DragonMake not found, not sure how we got here honestly.') - dberror('If you believe this message is in error, file an issue.') - dberror('https://github.com/DragonBuild/dragon') + dberror("Packager", 'DragonMake not found, not sure how we got here honestly.') + dberror("Packager", 'If you believe this message is in error, file an issue.') + dberror("Packager", 'https://github.com/DragonBuild/dragon') control = {keys[key]: value for (key, value) in config.items() if key in keys} @@ -77,20 +63,20 @@ def main(): if 'Name' not in control: control['Name'] = os.path.basename(os.getcwd()) # Warn for this bc it's kinda important - dbwarn(f'No "name:" key in DragonMake, guessing based on directory name ({control["Name"]})') + dbwarn("Packager", f'No "name:" key in DragonMake, guessing based on directory name ({control["Name"]})') if 'Package' not in control: control['Package'] = f'com.yourcompany.{control["Name"].lower()}' # Warn for this too, it's fairly important - dbwarn(f'No "id:" key in DragonMake, creating default based on `Name:` key') + dbwarn("Packager", f'No "id:" key in DragonMake, creating default based on `Name:` key') if 'Author' not in control: control['Author'] = os.getlogin() - dbwarn(f'No "Author:" key in DragonMake, guessing based on current user ({control["Author"]})') + dbwarn("Packager", f'No "Author:" key in DragonMake, guessing based on current user ({control["Author"]})') if 'Maintainer' not in control: control['Maintainer'] = control['Author'] - dbwarn(f'No "Maintainer:" key in DragonMake, creating default based on `Author:` key') + dbwarn("Packager", f'No "Maintainer:" key in DragonMake, creating default based on `Author:` key') # print(defs.update(control)) # print(control) @@ -103,7 +89,7 @@ def main(): for name in filenames: if name in config: - dbstate(f'Creating {name}') + dbstate("Packager", f'Creating {name}') with open(os.path.dirname(os.sys.argv[2]) + f'/{name}', 'w') as out: out.truncate() out.seek(0) diff --git a/src/dragongen/generation.py b/src/dragongen/generation.py index ad0a21330..18c227fc9 100644 --- a/src/dragongen/generation.py +++ b/src/dragongen/generation.py @@ -22,6 +22,7 @@ from .util import * from .toolchain import Toolchain from buildgen.generator import BuildFileGenerator +from shared.util import dbstate, dbwarn, dberror # Rules and defaults _LAZY_RULES_DOT_YML: dict = None @@ -197,10 +198,10 @@ def generate_vars(self, module_variables: dict, target: str) -> dict: toolchain = Toolchain.locate_linux_toolchain(use_objcs) if toolchain is None: - dberror("Could not locate any usable toolchain or even determine the existence of clang.") - dberror("If you're on macOS, install XCode and the Command Line Tools package") - dberror("If you're on linux, install sbingner's iOS toolchain to ~/.dragon/toolchain") - dberror("You can also add the key 'objcs': True to your DragonMake module to have dragon automatically" + dberror("Dragon Gen", "Could not locate any usable toolchain or even determine the existence of clang.") + dberror("Dragon Gen", "If you're on macOS, install XCode and the Command Line Tools package") + dberror("Dragon Gen", "If you're on linux, install sbingner's iOS toolchain to ~/.dragon/toolchain") + dberror("Dragon Gen", "You can also add the key 'objcs': True to your DragonMake module to have dragon automatically" "install its internal toolchain, however note this isn't really reccomended for non-objcs " "projects") exit(64) @@ -505,7 +506,7 @@ def get_default_section_dict(*key_path: str) -> dict: def handle(ex: Exception): """ Optionally print debug information """ - dberror("Press v for detailed debugging output, any other key to exit.") + dberror("Dragon Gen", "Press v for detailed debugging output, any other key to exit.") try: old_setting = termios.tcgetattr(sys.stdin.fileno()) @@ -513,12 +514,12 @@ def handle(ex: Exception): x = sys.stdin.read(1) termios.tcsetattr(0, termios.TCSADRAIN, old_setting) if str(x).lower() == 'v': - dberror(str(ex)) - dberror(''.join(traceback.format_tb(ex.__traceback__))) + dberror("Dragon Gen", str(ex)) + dberror("Dragon Gen", ''.join(traceback.format_tb(ex.__traceback__))) else: - dberror("Exiting...") + dberror("Dragon Gen", "Exiting...") except Exception: - dberror("Exiting...") + dberror("Dragon Gen", "Exiting...") print(f'export DRAGONGEN_FAILURE=1') @@ -576,12 +577,12 @@ def main(): # If that worked, it's the old (OLD) legacy DragonMake format, # which we can easily support via a couple lines of regex config = load_old_format(open('DragonMake')) - dbstate("Loading Legacy format DragonMake") + dbstate("Dragon Gen", "Loading Legacy format DragonMake") else: # bad format - dberror("Formatting Error in the DragonMake file") - dberror("Check YAML syntax or file an issue") - dberror('https://github.com/DragonBuild/dragon') + dberror("Dragon Gen", "Formatting Error in the DragonMake file") + dberror("Dragon Gen", "Check YAML syntax or file an issue") + dberror("Dragon Gen", 'https://github.com/DragonBuild/dragon') raise ex elif os.path.exists('Makefile'): @@ -589,14 +590,14 @@ def main(): config = TheosMakefileProcessor().project # config = interpret_theos_makefile(open('Makefile')) exports['theos'] = 1 - dbstate("Generating build scripts from Theos Makefile") + dbstate("Dragon Gen", "Generating build scripts from Theos Makefile") global _IS_THEOS_MAKEFILE_ _IS_THEOS_MAKEFILE_ = True else: raise FileNotFoundError - dbstate("Generating build scripts") + dbstate("Dragon Gen", "Generating build scripts") for key in config: if key in META_KEYS: continue @@ -615,9 +616,9 @@ def main(): except ValueError: # if i add a key to control.py and don't add it to meta tags here, this happens # so maybe find a better way to do that, dpkg is complex and has many fields - dbwarn("! Warning: Key %s is not a valid module (a dictionary)," + dbwarn("Dragon Gen", "! Warning: Key %s is not a valid module (a dictionary)," " nor is it a known configuration key" % key) - dbwarn("! This key will be ignored.") + dbwarn("Dragon Gen", "! This key will be ignored.") continue default_target = 'ios' @@ -627,10 +628,10 @@ def main(): with open(f'{submodule_config["dir"]}/{submodule_config["name"]}.ninja', 'w+') as out: try: generator = Generator(config, key, default_target) - dbstate(f"Creating build script for {key}") + dbstate("Dragon Gen", f"Creating build script for {key}") generator.write_output_file(out) except Exception as ex: - dberror(f'Exception in module "{key}":') + dberror("Dragon Gen", f'Exception in module "{key}":') raise ex dirs = dirs + ' ' + submodule_config['dir'] diff --git a/src/dragongen/util.py b/src/dragongen/util.py index 2d10a1090..49d9fada3 100644 --- a/src/dragongen/util.py +++ b/src/dragongen/util.py @@ -1,29 +1,11 @@ #!/usr/bin/env python3 -import os, sys, glob, inspect, termios, tty +import os, sys, glob, inspect import re as regex from enum import Enum from pprint import pprint, pformat from .variable_types import ArgList -colors = [["\033[0;31m", "\033[0;32m", "\033[0;33m", "\033[0;34m", "\033[0;36m", - "\033[0;37m", "\033[0m"], ["\033[1;31m", "\033[1;32m", "\033[1;33m", "\033[1;34m", - "\033[1;36m", "\033[1;37m", "\033[0m"]] - - -# Everything needs to go out of stderr *for now*. the bash script executes anything -# sent via stdout -# Also worth noting print() to stdout works like system() for us, except it's in the -# context of a shell above us -def dprintline(col: int, tool: str, textcol: int, bold: int, pusher: int, msg: str): - print("%s[%s]%s %s%s%s" % ( - colors[1][col], tool, colors[bold][textcol], ">>> " if pusher - else "", msg, colors[0][6]), file=sys.stderr) - - -dbstate = lambda msg: dprintline(1, "DragonGen", 5, 1, 0, msg) -dbwarn = lambda msg: dprintline(2, "DragonGen", 5, 0, 0, msg) -dberror = lambda msg: dprintline(0, "DragonGen", 5, 1, 0, msg) make_match = regex.compile('(.*)=(.*)#?') make_type = regex.compile(r'include.*\/(.*)\.mk') diff --git a/src/shared/util.py b/src/shared/util.py new file mode 100644 index 000000000..593ded5be --- /dev/null +++ b/src/shared/util.py @@ -0,0 +1,30 @@ +from enum import IntEnum +import sys + +class OutputColors(IntEnum): + Red = 31 + Green = 32 + Yellow = 33 + Blue = 34 + Cyan = 36 + White = 37 + Reset = 0 + +class OutputWeight(IntEnum): + Normal = 0 + Bold = 1 + +def color_string(output_color, output_weight): + return f'\033[{output_weight.value};{output_color.value}m' + +def dprintline(label_color, tool_name, text_color, text_weight, pusher, msg): + print(f"{color_string(label_color, OutputWeight.Bold)}[{tool_name}] {color_string(text_color, text_weight)}{'>>> ' if pusher else ''}{msg}{color_string(OutputColors.Reset, OutputWeight.Normal)}", file=sys.stderr) + +def dbstate(tool_name, msg): + dprintline(OutputColors.Green, tool_name, OutputColors.White, OutputWeight.Bold, False, msg) + +def dbwarn(tool_name, msg): + dprintline(OutputColors.Yellow, tool_name, OutputColors.White, OutputWeight.Normal, False, msg) + +def dberror(tool_name, msg): + dprintline(OutputColors.Red, tool_name, OutputColors.White, OutputWeight.Bold, False, msg)