1# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com> 2# 3# This file is part of Ansible 4# 5# Ansible is free software: you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published by 7# the Free Software Foundation, either version 3 of the License, or 8# (at your option) any later version. 9# 10# Ansible is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU General Public License for more details. 14# 15# You should have received a copy of the GNU General Public License 16# along with Ansible. If not, see <http://www.gnu.org/licenses/>. 17from __future__ import (absolute_import, division, print_function) 18__metaclass__ = type 19 20import re 21import sys 22 23from ansible import constants as C 24 25ANSIBLE_COLOR = True 26if C.ANSIBLE_NOCOLOR: 27 ANSIBLE_COLOR = False 28elif not hasattr(sys.stdout, 'isatty') or not sys.stdout.isatty(): 29 ANSIBLE_COLOR = False 30else: 31 try: 32 import curses 33 curses.setupterm() 34 if curses.tigetnum('colors') < 0: 35 ANSIBLE_COLOR = False 36 except ImportError: 37 # curses library was not found 38 pass 39 except curses.error: 40 # curses returns an error (e.g. could not find terminal) 41 ANSIBLE_COLOR = False 42 43if C.ANSIBLE_FORCE_COLOR: 44 ANSIBLE_COLOR = True 45 46# --- begin "pretty" 47# 48# pretty - A miniature library that provides a Python print and stdout 49# wrapper that makes colored terminal text easier to use (e.g. without 50# having to mess around with ANSI escape sequences). This code is public 51# domain - there is no license except that you must leave this header. 52# 53# Copyright (C) 2008 Brian Nez <thedude at bri1 dot com> 54 55 56def parsecolor(color): 57 """SGR parameter string for the specified color name.""" 58 matches = re.match(r"color(?P<color>[0-9]+)" 59 r"|(?P<rgb>rgb(?P<red>[0-5])(?P<green>[0-5])(?P<blue>[0-5]))" 60 r"|gray(?P<gray>[0-9]+)", color) 61 if not matches: 62 return C.COLOR_CODES[color] 63 if matches.group('color'): 64 return u'38;5;%d' % int(matches.group('color')) 65 if matches.group('rgb'): 66 return u'38;5;%d' % (16 + 36 * int(matches.group('red')) + 67 6 * int(matches.group('green')) + 68 int(matches.group('blue'))) 69 if matches.group('gray'): 70 return u'38;5;%d' % (232 + int(matches.group('gray'))) 71 72 73def stringc(text, color, wrap_nonvisible_chars=False): 74 """String in color.""" 75 76 if ANSIBLE_COLOR: 77 color_code = parsecolor(color) 78 fmt = u"\033[%sm%s\033[0m" 79 if wrap_nonvisible_chars: 80 # This option is provided for use in cases when the 81 # formatting of a command line prompt is needed, such as 82 # `ansible-console`. As said in `readline` sources: 83 # readline/display.c:321 84 # /* Current implementation: 85 # \001 (^A) start non-visible characters 86 # \002 (^B) end non-visible characters 87 # all characters except \001 and \002 (following a \001) are copied to 88 # the returned string; all characters except those between \001 and 89 # \002 are assumed to be `visible'. */ 90 fmt = u"\001\033[%sm\002%s\001\033[0m\002" 91 return u"\n".join([fmt % (color_code, t) for t in text.split(u'\n')]) 92 else: 93 return text 94 95 96def colorize(lead, num, color): 97 """ Print 'lead' = 'num' in 'color' """ 98 s = u"%s=%-4s" % (lead, str(num)) 99 if num != 0 and ANSIBLE_COLOR and color is not None: 100 s = stringc(s, color) 101 return s 102 103 104def hostcolor(host, stats, color=True): 105 if ANSIBLE_COLOR and color: 106 if stats['failures'] != 0 or stats['unreachable'] != 0: 107 return u"%-37s" % stringc(host, C.COLOR_ERROR) 108 elif stats['changed'] != 0: 109 return u"%-37s" % stringc(host, C.COLOR_CHANGED) 110 else: 111 return u"%-37s" % stringc(host, C.COLOR_OK) 112 return u"%-26s" % host 113