Loading .gitignore 0 → 100644 +7 −0 Original line number Diff line number Diff line */__pycache__/ *.pyc *~ *.dbm */raw/ .idea/ __init__.py 0 → 100644 +2 −0 Original line number Diff line number Diff line #!/usr/bin/env python3 No newline at end of file color.py 0 → 100644 +107 −0 Original line number Diff line number Diff line #!/usr/bin/env python3 import sys import re IS_COLOR: bool = True if not hasattr(sys.stdout, 'isatty') or not sys.stdout.isatty(): IS_COLOR = False else: try: import curses curses.setupterm() if curses.tigetnum('colors') < 0: IS_COLOR = False except ImportError: # curses library was not found pass except curses.error: # curses returns an error (e.g. could not find terminal) IS_COLOR = False # if C.IS_FORCE_COLOR: # IS_COLOR = True class BColors: HEADER = '\033[95m' OKBLUE = '\033[94m' CHANGED = '\033[94m' OKGREEN = '\033[92m' WARNING = '\033[93m' ERROR = '\033[91m' ENDC = '\033[0m' BOLD = '\033[1m' UNDERLINE = '\033[4m' # --- begin "pretty" # # pretty - A miniature library that provides a Python print and stdout # wrapper that makes colored terminal text easier to use (e.g. without # having to mess around with ANSI escape sequences). This code is public # domain - there is no license except that you must leave this header. # # Copyright (C) 2008 Brian Nez <thedude at bri1 dot com> # # http://nezzen.net/2008/06/23/colored-text-in-python-using-ansi-escape-sequences/ codeCodes = { 'black': u'0;30', 'bright gray': u'0;37', 'blue': u'0;34', 'white': u'1;37', 'green': u'0;32', 'bright blue': u'1;34', 'cyan': u'0;36', 'bright green': u'1;32', 'red': u'0;31', 'bright cyan': u'1;36', 'purple': u'0;35', 'bright red': u'1;31', 'yellow': u'0;33', 'bright purple': u'1;35', 'dark gray': u'1;30', 'bright yellow': u'1;33', 'magenta': u'0;35', 'bright magenta': u'1;35', 'normal': u'0', } def parsecolor(color): """SGR parameter string for the specified color name.""" matches = re.match(r"color(?P<color>[0-9]+)" r"|(?P<rgb>rgb(?P<red>[0-5])(?P<green>[0-5])(?P<blue>[0-5]))" r"|gray(?P<gray>[0-9]+)", color) if not matches: return codeCodes[color] if matches.group('color'): return '38;5;%d' % int(matches.group('color')) if matches.group('rgb'): return '38;5;%d' % (16 + 36 * int(matches.group('red')) + 6 * int(matches.group('green')) + int(matches.group('blue'))) if matches.group('gray'): return '38;5;%d' % (232 + int(matches.group('gray'))) def stringc(text: str, color) -> str: """String in color.""" if IS_COLOR: color_code = parsecolor(color) return "\n".join(["\033[%sm%s\033[0m" % (color_code, t) for t in text.split('\n')]) else: return text def colorize(lead, num, color): """ Print 'lead' = 'num' in 'color' """ s = "%s=%-4s" % (lead, str(num)) if num != 0 and IS_COLOR and color is not None: s = stringc(s, color) return s def hostcolor(host: str, stats: list, color: bool = True) -> str: if IS_COLOR and color: if stats['failures'] != 0 or stats['unreachable'] != 0: return "%-37s" % stringc(host, BColors.ERROR) elif stats['changed'] != 0: return "%-37s" % stringc(host, BColors.CHANGED) else: return "%-37s" % stringc(host, BColors.OKGREEN) return "%-26s" % host display.py 0 → 100644 +105 −0 Original line number Diff line number Diff line #!/usr/bin/env python3 import os import sys import errno import time from utils.color import stringc from utils.color import BColors from utils.parsing import to_text from utils.singleton import Singleton from config import constants as C from utils.six import with_metaclass class Display(with_metaclass(Singleton, object)): def __init__(self, verbosity: int=0): self.columns = None self.verbosity = verbosity # list of all deprecation messages to prevent duplicate display self._deprecations = {} self._warns = {} self._errors = {} def display(self, msg, color=None, stderr=False, screen_only=False, log_only=False): """ Display a message to the user Note: msg *must* be a unicode string to prevent UnicodeError tracebacks. """ nocolor = msg if color: msg = stringc(msg, color) if not log_only: if not msg.endswith('\n'): msg2 = msg + '\n' else: msg2 = msg msg2 = to_text(msg2) if not stderr: fileobj = sys.stdout else: fileobj = sys.stderr fileobj.write(msg2) try: fileobj.flush() except IOError as e: # Ignore EPIPE in case fileobj has been prematurely closed, eg. # when piping to "head -n1" if e.errno != errno.EPIPE: raise def v(self, msg, host=None): return self.verbose(msg, host=host, caplevel=0) def vv(self, msg, host=None): return self.verbose(msg, host=host, caplevel=1) def vvv(self, msg, host=None): return self.verbose(msg, host=host, caplevel=2) def vvvv(self, msg, host=None): return self.verbose(msg, host=host, caplevel=3) def vvvvv(self, msg, host=None): return self.verbose(msg, host=host, caplevel=4) def vvvvvv(self, msg, host=None): return self.verbose(msg, host=host, caplevel=5) def debug(self, msg, host=None): # TODO TODO if C.DEFAULT_DEBUG: if host is None: self.display("%6d %0.5f: %s" % (os.getpid(), time.time(), msg), color=C.COLOR_DEBUG) else: self.display("%6d %0.5f [%s]: %s" % (os.getpid(), time.time(), host, msg), color=C.COLOR_DEBUG) def verbose(self, msg, host=None, caplevel=2): to_stderr = C.VERBOSE_TO_STDERR if self.verbosity > caplevel: if host is None: self.display(msg, color=C.COLOR_VERBOSE, stderr=to_stderr) else: self.display("<%s> %s" % (host, msg), color=C.COLOR_VERBOSE, stderr=to_stderr) @classmethod def deprecated(cls, message: str): pass @classmethod def warning(cls, message: str): pass No newline at end of file errors.py 0 → 100644 +22 −0 Original line number Diff line number Diff line #!/usr/bin/env python3 class AMMSMLError(Exception): pass class AMMSMLParserError(AMMSMLError): pass class TemplateParsingError(AMMSMLError): """a templating failure""" pass class AMMSMLOptionsError(AMMSMLError): pass Loading
.gitignore 0 → 100644 +7 −0 Original line number Diff line number Diff line */__pycache__/ *.pyc *~ *.dbm */raw/ .idea/
__init__.py 0 → 100644 +2 −0 Original line number Diff line number Diff line #!/usr/bin/env python3 No newline at end of file
color.py 0 → 100644 +107 −0 Original line number Diff line number Diff line #!/usr/bin/env python3 import sys import re IS_COLOR: bool = True if not hasattr(sys.stdout, 'isatty') or not sys.stdout.isatty(): IS_COLOR = False else: try: import curses curses.setupterm() if curses.tigetnum('colors') < 0: IS_COLOR = False except ImportError: # curses library was not found pass except curses.error: # curses returns an error (e.g. could not find terminal) IS_COLOR = False # if C.IS_FORCE_COLOR: # IS_COLOR = True class BColors: HEADER = '\033[95m' OKBLUE = '\033[94m' CHANGED = '\033[94m' OKGREEN = '\033[92m' WARNING = '\033[93m' ERROR = '\033[91m' ENDC = '\033[0m' BOLD = '\033[1m' UNDERLINE = '\033[4m' # --- begin "pretty" # # pretty - A miniature library that provides a Python print and stdout # wrapper that makes colored terminal text easier to use (e.g. without # having to mess around with ANSI escape sequences). This code is public # domain - there is no license except that you must leave this header. # # Copyright (C) 2008 Brian Nez <thedude at bri1 dot com> # # http://nezzen.net/2008/06/23/colored-text-in-python-using-ansi-escape-sequences/ codeCodes = { 'black': u'0;30', 'bright gray': u'0;37', 'blue': u'0;34', 'white': u'1;37', 'green': u'0;32', 'bright blue': u'1;34', 'cyan': u'0;36', 'bright green': u'1;32', 'red': u'0;31', 'bright cyan': u'1;36', 'purple': u'0;35', 'bright red': u'1;31', 'yellow': u'0;33', 'bright purple': u'1;35', 'dark gray': u'1;30', 'bright yellow': u'1;33', 'magenta': u'0;35', 'bright magenta': u'1;35', 'normal': u'0', } def parsecolor(color): """SGR parameter string for the specified color name.""" matches = re.match(r"color(?P<color>[0-9]+)" r"|(?P<rgb>rgb(?P<red>[0-5])(?P<green>[0-5])(?P<blue>[0-5]))" r"|gray(?P<gray>[0-9]+)", color) if not matches: return codeCodes[color] if matches.group('color'): return '38;5;%d' % int(matches.group('color')) if matches.group('rgb'): return '38;5;%d' % (16 + 36 * int(matches.group('red')) + 6 * int(matches.group('green')) + int(matches.group('blue'))) if matches.group('gray'): return '38;5;%d' % (232 + int(matches.group('gray'))) def stringc(text: str, color) -> str: """String in color.""" if IS_COLOR: color_code = parsecolor(color) return "\n".join(["\033[%sm%s\033[0m" % (color_code, t) for t in text.split('\n')]) else: return text def colorize(lead, num, color): """ Print 'lead' = 'num' in 'color' """ s = "%s=%-4s" % (lead, str(num)) if num != 0 and IS_COLOR and color is not None: s = stringc(s, color) return s def hostcolor(host: str, stats: list, color: bool = True) -> str: if IS_COLOR and color: if stats['failures'] != 0 or stats['unreachable'] != 0: return "%-37s" % stringc(host, BColors.ERROR) elif stats['changed'] != 0: return "%-37s" % stringc(host, BColors.CHANGED) else: return "%-37s" % stringc(host, BColors.OKGREEN) return "%-26s" % host
display.py 0 → 100644 +105 −0 Original line number Diff line number Diff line #!/usr/bin/env python3 import os import sys import errno import time from utils.color import stringc from utils.color import BColors from utils.parsing import to_text from utils.singleton import Singleton from config import constants as C from utils.six import with_metaclass class Display(with_metaclass(Singleton, object)): def __init__(self, verbosity: int=0): self.columns = None self.verbosity = verbosity # list of all deprecation messages to prevent duplicate display self._deprecations = {} self._warns = {} self._errors = {} def display(self, msg, color=None, stderr=False, screen_only=False, log_only=False): """ Display a message to the user Note: msg *must* be a unicode string to prevent UnicodeError tracebacks. """ nocolor = msg if color: msg = stringc(msg, color) if not log_only: if not msg.endswith('\n'): msg2 = msg + '\n' else: msg2 = msg msg2 = to_text(msg2) if not stderr: fileobj = sys.stdout else: fileobj = sys.stderr fileobj.write(msg2) try: fileobj.flush() except IOError as e: # Ignore EPIPE in case fileobj has been prematurely closed, eg. # when piping to "head -n1" if e.errno != errno.EPIPE: raise def v(self, msg, host=None): return self.verbose(msg, host=host, caplevel=0) def vv(self, msg, host=None): return self.verbose(msg, host=host, caplevel=1) def vvv(self, msg, host=None): return self.verbose(msg, host=host, caplevel=2) def vvvv(self, msg, host=None): return self.verbose(msg, host=host, caplevel=3) def vvvvv(self, msg, host=None): return self.verbose(msg, host=host, caplevel=4) def vvvvvv(self, msg, host=None): return self.verbose(msg, host=host, caplevel=5) def debug(self, msg, host=None): # TODO TODO if C.DEFAULT_DEBUG: if host is None: self.display("%6d %0.5f: %s" % (os.getpid(), time.time(), msg), color=C.COLOR_DEBUG) else: self.display("%6d %0.5f [%s]: %s" % (os.getpid(), time.time(), host, msg), color=C.COLOR_DEBUG) def verbose(self, msg, host=None, caplevel=2): to_stderr = C.VERBOSE_TO_STDERR if self.verbosity > caplevel: if host is None: self.display(msg, color=C.COLOR_VERBOSE, stderr=to_stderr) else: self.display("<%s> %s" % (host, msg), color=C.COLOR_VERBOSE, stderr=to_stderr) @classmethod def deprecated(cls, message: str): pass @classmethod def warning(cls, message: str): pass No newline at end of file
errors.py 0 → 100644 +22 −0 Original line number Diff line number Diff line #!/usr/bin/env python3 class AMMSMLError(Exception): pass class AMMSMLParserError(AMMSMLError): pass class TemplateParsingError(AMMSMLError): """a templating failure""" pass class AMMSMLOptionsError(AMMSMLError): pass