From 12ff9b5b9a54fb006ff3d1ca67bc4d22457f81d5 Mon Sep 17 00:00:00 2001 From: Michael DeHaan Date: Tue, 24 Jul 2012 19:30:02 -0400 Subject: [PATCH] Move color coding bits to module, use over rest of playbook --- bin/ansible-playbook | 49 +++++------------------------- lib/ansible/callbacks.py | 65 +++++++++++++++++++++++++++------------- lib/ansible/color.py | 59 ++++++++++++++++++++++++++++++++++++ lib/ansible/utils.py | 3 ++ 4 files changed, 114 insertions(+), 62 deletions(-) create mode 100644 lib/ansible/color.py diff --git a/bin/ansible-playbook b/bin/ansible-playbook index e69ec02bd4a..cce371e2bd6 100755 --- a/bin/ansible-playbook +++ b/bin/ansible-playbook @@ -27,47 +27,10 @@ import ansible.constants as C from ansible import errors from ansible import callbacks from ansible import utils - -ANSIBLE_COLOR=True -if os.getenv("ANSIBLE_NOCOLOR") is not None: - ANSIBLE_COLOR=False -if not sys.stdout.isatty(): - ANSIBLE_COLOR=False - -# --- begin "pretty" -# -# pretty - A miniature library that provides a Python print and stdout -# wrapper that makes colored terminal text easier to use (eg. 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 -# -# http://nezzen.net/2008/06/23/colored-text-in-python-using-ansi-escape-sequences/ - - -codeCodes = { - 'black': '0;30', 'bright gray': '0;37', - 'blue': '0;34', 'white': '1;37', - 'green': '0;32', 'bright blue': '1;34', - 'cyan': '0;36', 'bright green': '1;32', - 'red': '0;31', 'bright cyan': '1;36', - 'purple': '0;35', 'bright red': '1;31', - 'yellow': '0;33', 'bright purple': '1;35', - 'dark gray': '1;30', 'bright yellow': '1;33', - 'normal': '0' -} - -def stringc(text, color): - """String in color.""" - if ANSIBLE_COLOR: - return "\033["+codeCodes[color]+"m"+text+"\033[0m" - else: - return text -# --- end "pretty" +from ansible.color import ANSIBLE_COLOR, stringc def colorize(lead, num, color): - """Print `lead' = `num' in `color'""" + """ Print 'lead' = 'num' in 'color' """ if num == 0: color='black'; if ANSIBLE_COLOR: @@ -75,10 +38,14 @@ def colorize(lead, num, color): else: return "%s=%-4s" % (lead, str(num)) -def hostcolor(host, t): +def hostcolor(host, stats): if ANSIBLE_COLOR: - if t['failures'] != 0 or t['unreachable'] != 0: + if stats['failures'] != 0 or stats['unreachable'] != 0: return "%-41s" % stringc(host, 'red') + elif stats['changed'] != 0: + return "%-41s" % stringc(host, 'yellow') + else: + return "%-41s" % stringc(host, 'green') return "%-30s" % host diff --git a/lib/ansible/callbacks.py b/lib/ansible/callbacks.py index fc8d29162fe..85dd31cdd27 100644 --- a/lib/ansible/callbacks.py +++ b/lib/ansible/callbacks.py @@ -20,6 +20,7 @@ import sys import getpass import os import subprocess +from ansible.color import stringc cowsay = None if os.path.exists("/usr/bin/cowsay"): @@ -125,17 +126,18 @@ def host_report_msg(hostname, module_name, result, oneline): ''' summarize the JSON results for a particular host ''' failed = utils.is_failed(result) + msg = '' if module_name in [ 'command', 'shell', 'raw' ] and 'ansible_job_id' not in result: if not failed: - return command_generic_msg(hostname, result, oneline, 'success') + msg = command_generic_msg(hostname, result, oneline, 'success') else: - return command_generic_msg(hostname, result, oneline, 'FAILED') + msg = command_generic_msg(hostname, result, oneline, 'FAILED') else: if not failed: - return regular_generic_msg(hostname, result, oneline, 'success') + msg = regular_generic_msg(hostname, result, oneline, 'success') else: - return regular_generic_msg(hostname, result, oneline, 'FAILED') - + msg = regular_generic_msg(hostname, result, oneline, 'FAILED') + return msg ############################################### @@ -262,45 +264,62 @@ class PlaybookRunnerCallbacks(DefaultRunnerCallbacks): item = results.get('item', None) if item: - print "failed: [%s] => (item=%s) => %s" % (host, item, utils.jsonify(results)) + msg = "failed: [%s] => (item=%s) => %s" % (host, item, utils.jsonify(results)) else: - print "failed: [%s] => %s" % (host, utils.jsonify(results)) + msg = "failed: [%s] => %s" % (host, utils.jsonify(results)) + + return color.string(msg, 'red') def on_ok(self, host, host_result): item = host_result.get('item', None) # show verbose output for non-setup module results if --verbose is used + msg = '' if not self.verbose or host_result.get("verbose_override",None) is not None: if item: - print "ok: [%s] => (item=%s)" % (host,item) + msg = "ok: [%s] => (item=%s)" % (host,item) else: - print "ok: [%s]" % (host) + if 'ansible_job_id' not in host_result or 'finished' in host_result: + msg = "ok: [%s]" % (host) else: + # verbose ... if item: - print "ok: [%s] => (item=%s) => %s" % (host, item, utils.jsonify(host_result)) + msg = "ok: [%s] => (item=%s) => %s" % (host, item, utils.jsonify(host_result)) else: - print "ok: [%s] => %s" % (host, utils.jsonify(host_result)) + if 'ansible_job_id' not in host_result or 'finished' in host_result: + msg = "ok: [%s] => %s" % (host, utils.jsonify(host_result)) + + if msg != '': + if not 'changed' in host_result or not host_result['changed']: + print stringc(msg, 'green') + else: + print stringc(msg, 'yellow') def on_error(self, host, err): item = err.get('item', None) - + msg = '' if item: - print >>sys.stderr, "err: [%s] => (item=%s) => %s" % (host, item, err) + msg = "err: [%s] => (item=%s) => %s" % (host, item, err) else: - print >>sys.stderr, "err: [%s] => %s" % (host, err) + msg = "err: [%s] => %s" % (host, err) + + msg = stringc(msg, 'red') + print >>sys.stderr, msg def on_skipped(self, host, item=None): - if item: - print "skipping: [%s] => (item=%s)" % (host, item) + msg = '' + if item: + msg = "skipping: [%s] => (item=%s)" % (host, item) else: - print "skipping: [%s]" % host + msg = "skipping: [%s]" % host + print stringc(msg, 'yellow') def on_no_hosts(self): - print "no hosts matched or remaining\n" + print stringc("no hosts matched or remaining\n", 'orange') def on_async_poll(self, host, res, jid, clock): @@ -308,15 +327,19 @@ class PlaybookRunnerCallbacks(DefaultRunnerCallbacks): self._async_notified[jid] = clock + 1 if self._async_notified[jid] > clock: self._async_notified[jid] = clock - print " polling, %ss remaining"%(jid, clock) + msg = " polling, %ss remaining"%(jid, clock) + print stringc(msg, 'blue') def on_async_ok(self, host, res, jid): - print " finished on %s"%(jid, host) + msg = " finished on %s"%(jid, host) + print stringc(msg, 'blue') def on_async_failed(self, host, res, jid): - print " FAILED on %s"%(jid, host) + msg = " FAILED on %s"%(jid, host) + print stringc(msg, 'red') + ######################################################################## diff --git a/lib/ansible/color.py b/lib/ansible/color.py new file mode 100644 index 00000000000..8a67b232721 --- /dev/null +++ b/lib/ansible/color.py @@ -0,0 +1,59 @@ +# (c) 2012, Michael DeHaan +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +import os +import sys + +ANSIBLE_COLOR=True +if os.getenv("ANSIBLE_NOCOLOR") is not None: + ANSIBLE_COLOR=False +if not sys.stdout.isatty(): + ANSIBLE_COLOR=False + +# --- begin "pretty" +# +# pretty - A miniature library that provides a Python print and stdout +# wrapper that makes colored terminal text easier to use (eg. 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 +# +# http://nezzen.net/2008/06/23/colored-text-in-python-using-ansi-escape-sequences/ + +codeCodes = { + 'black': '0;30', 'bright gray': '0;37', + 'blue': '0;34', 'white': '1;37', + 'green': '0;32', 'bright blue': '1;34', + 'cyan': '0;36', 'bright green': '1;32', + 'red': '0;31', 'bright cyan': '1;36', + 'purple': '0;35', 'bright red': '1;31', + 'yellow': '0;33', 'bright purple': '1;35', + 'dark gray': '1;30', 'bright yellow': '1;33', + 'normal': '0' +} + +def stringc(text, color): + """String in color.""" + + if ANSIBLE_COLOR: + return "\033["+codeCodes[color]+"m"+text+"\033[0m" + else: + return text + +# --- end "pretty" + diff --git a/lib/ansible/utils.py b/lib/ansible/utils.py index 7d64264e134..c8bab97397d 100644 --- a/lib/ansible/utils.py +++ b/lib/ansible/utils.py @@ -25,6 +25,7 @@ import yaml import optparse import operator from ansible import errors +from ansible import color import ansible.constants as C try: @@ -329,3 +330,5 @@ def base_parser(constants=C, usage="", output_opts=False, runas_opts=False, asyn return parser + +