File: //usr/lib/python2.7/site-packages/salt/output/__init__.py
# -*- coding: utf-8 -*-
'''
Used to manage the outputter system. This package is the modular system used
for managing outputters.
'''
# Import Python libs
from __future__ import absolute_import, print_function, unicode_literals
import errno
import logging
import io
import os
import re
import sys
import traceback
# Import Salt libs
import salt.loader
import salt.utils.files
import salt.utils.platform
import salt.utils.stringutils
# Import 3rd-party libs
from salt.ext import six
# Are you really sure !!!
# dealing with unicode is not as simple as setting defaultencoding
# which can break other python modules imported by salt in bad ways...
# reloading sys is not either a good idea...
# reload(sys)
# sys.setdefaultencoding('utf-8')
log = logging.getLogger(__name__)
def try_printout(data, out, opts, **kwargs):
'''
Safely get the string to print out, try the configured outputter, then
fall back to nested and then to raw
'''
try:
printout = get_printout(out, opts)(data, **kwargs)
if printout is not None:
return printout.rstrip()
except (KeyError, AttributeError, TypeError):
log.debug(traceback.format_exc())
try:
printout = get_printout('nested', opts)(data, **kwargs)
if printout is not None:
return printout.rstrip()
except (KeyError, AttributeError, TypeError):
log.error('Nested output failed: ', exc_info=True)
printout = get_printout('raw', opts)(data, **kwargs)
if printout is not None:
return printout.rstrip()
def get_progress(opts, out, progress):
'''
Get the progress bar from the given outputter
'''
return salt.loader.raw_mod(opts,
out,
'rawmodule',
mod='output')['{0}.progress_iter'.format(out)](progress)
def update_progress(opts, progress, progress_iter, out):
'''
Update the progress iterator for the given outputter
'''
# Look up the outputter
try:
progress_outputter = salt.loader.outputters(opts)[out]
except KeyError: # Outputter is not loaded
log.warning('Progress outputter not available.')
return False
progress_outputter(progress, progress_iter)
def progress_end(progress_iter):
try:
progress_iter.stop()
except Exception: # pylint: disable=broad-except
pass
return None
def display_output(data, out=None, opts=None, **kwargs):
'''
Print the passed data using the desired output
'''
if opts is None:
opts = {}
display_data = try_printout(data, out, opts, **kwargs)
output_filename = opts.get('output_file', None)
log.trace('data = %s', data)
try:
# output filename can be either '' or None
if output_filename:
if not hasattr(output_filename, 'write'):
ofh = salt.utils.files.fopen(output_filename, 'a') # pylint: disable=resource-leakage
fh_opened = True
else:
# Filehandle/file-like object
ofh = output_filename
fh_opened = False
try:
fdata = display_data
if isinstance(fdata, six.text_type):
try:
fdata = fdata.encode('utf-8')
except (UnicodeDecodeError, UnicodeEncodeError):
# try to let the stream write
# even if we didn't encode it
pass
if fdata:
ofh.write(salt.utils.stringutils.to_str(fdata))
ofh.write('\n')
finally:
if fh_opened:
ofh.close()
return
if display_data:
salt.utils.stringutils.print_cli(display_data)
except IOError as exc:
# Only raise if it's NOT a broken pipe
if exc.errno != errno.EPIPE:
six.reraise(*sys.exc_info())
def get_printout(out, opts=None, **kwargs):
'''
Return a printer function
'''
if opts is None:
opts = {}
if 'output' in opts and opts['output'] != 'highstate':
# new --out option, but don't choke when using --out=highstate at CLI
# See Issue #29796 for more information.
out = opts['output']
# Handle setting the output when --static is passed.
if not out and opts.get('static'):
if opts.get('output'):
out = opts['output']
elif opts.get('fun', '').split('.')[0] == 'state':
# --static doesn't have an output set at this point, but if we're
# running a state function and "out" hasn't already been set, we
# should set the out variable to "highstate". Otherwise state runs
# are set to "nested" below. See Issue #44556 for more information.
out = 'highstate'
if out == 'text':
out = 'txt'
elif out is None or out == '':
out = 'nested'
if opts.get('progress', False):
out = 'progress'
opts.update(kwargs)
if 'color' not in opts:
def is_pipe():
'''
Check if sys.stdout is a pipe or not
'''
try:
fileno = sys.stdout.fileno()
except (AttributeError, io.UnsupportedOperation):
fileno = -1 # sys.stdout is StringIO or fake
return not os.isatty(fileno)
if opts.get('force_color', False):
opts['color'] = True
elif opts.get('no_color', False) or is_pipe() or salt.utils.platform.is_windows():
opts['color'] = False
else:
opts['color'] = True
else:
if opts.get('force_color', False):
opts['color'] = True
elif opts.get('no_color', False) or salt.utils.platform.is_windows():
opts['color'] = False
else:
pass
outputters = salt.loader.outputters(opts)
if out not in outputters:
# Since the grains outputter was removed we don't need to fire this
# error when old minions are asking for it
if out != 'grains':
log.error(
'Invalid outputter %s specified, fall back to nested',
out,
)
return outputters['nested']
return outputters[out]
def out_format(data, out, opts=None, **kwargs):
'''
Return the formatted outputter string for the passed data
'''
return try_printout(data, out, opts, **kwargs)
def string_format(data, out, opts=None, **kwargs):
'''
Return the formatted outputter string, removing the ANSI escape sequences.
'''
raw_output = try_printout(data, out, opts, **kwargs)
ansi_escape = re.compile(r'\x1b[^m]*m')
return ansi_escape.sub('', raw_output)
def html_format(data, out, opts=None, **kwargs):
'''
Return the formatted string as HTML.
'''
ansi_escaped_string = string_format(data, out, opts, **kwargs)
return ansi_escaped_string.replace(' ', ' ').replace('\n', '<br />')
def strip_esc_sequence(txt):
'''
Replace ESC (ASCII 27/Oct 33) to prevent unsafe strings
from writing their own terminal manipulation commands
'''
if isinstance(txt, six.string_types):
try:
return txt.replace('\033', '?')
except UnicodeDecodeError:
return txt.replace(str('\033'), str('?')) # future lint: disable=blacklisted-function
else:
return txt