Mini Shell
"""
Used to manage the outputter system. This package is the modular system used
for managing outputters.
"""
import errno
import io
import logging
import os
import re
import sys
import traceback
import salt.loader
import salt.utils.files
import salt.utils.platform
import salt.utils.stringutils
# 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")[
f"{out}.progress_iter"
](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"):
# pylint: disable=resource-leakage
ofh = salt.utils.files.fopen(output_filename, "a")
# pylint: enable=resource-leakage
fh_opened = True
else:
# Filehandle/file-like object
ofh = output_filename
fh_opened = False
try:
fdata = display_data
if isinstance(fdata, str):
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 OSError as exc:
# Only raise if it's NOT a broken pipe
if exc.errno != errno.EPIPE:
raise
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, str):
return txt.replace("\033", "?")
else:
return txt
Zerion Mini Shell 1.0