summaryrefslogtreecommitdiff
path: root/buildstream/_frontend
diff options
context:
space:
mode:
authorTristan Van Berkom <tristan.vanberkom@codethink.co.uk>2018-04-15 20:06:17 +0900
committerTristan Van Berkom <tristan.vanberkom@codethink.co.uk>2018-04-15 20:10:01 +0900
commite769beca15b333f0feafc7e67a9437b3f988c518 (patch)
treee375a9b115bfe63563181646195ba74792c6f551 /buildstream/_frontend
parent219c7d2998f3259de1beff4f7d74f1a4423321c4 (diff)
downloadbuildstream-e769beca15b333f0feafc7e67a9437b3f988c518.tar.gz
_frontend/widget.py: Adhere to policy on private symbols
This is a part of issue #285
Diffstat (limited to 'buildstream/_frontend')
-rw-r--r--buildstream/_frontend/widget.py576
1 files changed, 307 insertions, 269 deletions
diff --git a/buildstream/_frontend/widget.py b/buildstream/_frontend/widget.py
index f5e08ad08..a07ae0c32 100644
--- a/buildstream/_frontend/widget.py
+++ b/buildstream/_frontend/widget.py
@@ -128,7 +128,7 @@ class Debug(Widget):
# A widget for rendering the time codes
class TimeCode(Widget):
def __init__(self, content_profile, format_profile, microseconds=False):
- self.microseconds = microseconds
+ self._microseconds = microseconds
super(TimeCode, self).__init__(content_profile, format_profile)
def render(self, message):
@@ -150,7 +150,7 @@ class TimeCode(Widget):
text = self.format_profile.fmt(':').join(fields)
- if self.microseconds:
+ if self._microseconds:
if elapsed is not None:
text += self.content_profile.fmt(".{0:06d}".format(elapsed.microseconds))
else:
@@ -161,7 +161,7 @@ class TimeCode(Widget):
# A widget for rendering the MessageType
class TypeName(Widget):
- action_colors = {
+ _action_colors = {
MessageType.DEBUG: "cyan",
MessageType.STATUS: "cyan",
MessageType.INFO: "magenta",
@@ -177,7 +177,7 @@ class TypeName(Widget):
return self.content_profile.fmt("{: <7}"
.format(message.message_type.upper()),
bold=True, dim=True,
- fg=self.action_colors[message.message_type])
+ fg=self._action_colors[message.message_type])
# A widget for displaying the Element name
@@ -188,7 +188,7 @@ class ElementName(Widget):
# Pre initialization format string, before we know the length of
# element names in the pipeline
- self.fmt_string = '{: <30}'
+ self._fmt_string = '{: <30}'
def size_request(self, pipeline):
longest_name = 0
@@ -198,7 +198,7 @@ class ElementName(Widget):
# Put a cap at a specific width, usually some elements cause the line
# to be too long, just live with the unaligned columns in that case
longest_name = min(longest_name, 30)
- self.fmt_string = '{: <' + str(longest_name) + '}'
+ self._fmt_string = '{: <' + str(longest_name) + '}'
def render(self, message):
element_id = message.task_id or message.unique_id
@@ -215,7 +215,7 @@ class ElementName(Widget):
return self.content_profile.fmt("{: >5}".format(action_name.lower())) + \
self.format_profile.fmt(':') + \
- self.content_profile.fmt(self.fmt_string.format(name))
+ self.content_profile.fmt(self._fmt_string.format(name))
# A widget for displaying the primary message text
@@ -232,26 +232,26 @@ class CacheKey(Widget):
def __init__(self, content_profile, format_profile, err_profile):
super(CacheKey, self).__init__(content_profile, format_profile)
- self.err_profile = err_profile
- self.key_length = 0
+ self._err_profile = err_profile
+ self._key_length = 0
def size_request(self, pipeline):
- self.key_length = pipeline.context.log_key_length
+ self._key_length = pipeline.context.log_key_length
def render(self, message):
element_id = message.task_id or message.unique_id
- if element_id is None or not self.key_length:
+ if element_id is None or not self._key_length:
return ""
missing = False
- key = ' ' * self.key_length
+ key = ' ' * self._key_length
plugin = _plugin_lookup(element_id)
if isinstance(plugin, Element):
_, key, missing = plugin._get_display_key()
if message.message_type in ERROR_MESSAGES:
- text = self.err_profile.fmt(key)
+ text = self._err_profile.fmt(key)
else:
text = self.content_profile.fmt(key, dim=missing)
@@ -264,25 +264,25 @@ class LogFile(Widget):
def __init__(self, content_profile, format_profile, err_profile):
super(LogFile, self).__init__(content_profile, format_profile)
- self.err_profile = err_profile
- self.logdir = ''
+ self._err_profile = err_profile
+ self._logdir = ''
def size_request(self, pipeline):
# Hold on to the logging directory so we can abbreviate
- self.logdir = pipeline.context.logdir
+ self._logdir = pipeline.context.logdir
def render(self, message, abbrev=True):
if message.logfile and message.scheduler:
logfile = message.logfile
- if abbrev and self.logdir != "" and logfile.startswith(self.logdir):
- logfile = logfile[len(self.logdir):]
+ if abbrev and self._logdir != "" and logfile.startswith(self._logdir):
+ logfile = logfile[len(self._logdir):]
logfile = logfile.lstrip(os.sep)
if message.message_type in ERROR_MESSAGES:
- text = self.err_profile.fmt(logfile)
+ text = self._err_profile.fmt(logfile)
else:
text = self.content_profile.fmt(logfile, dim=True)
else:
@@ -291,27 +291,27 @@ class LogFile(Widget):
return text
+# START and SUCCESS messages are expected to have no useful
+# information in the message text, so we display the logfile name for
+# these messages, and the message text for other types.
+#
class MessageOrLogFile(Widget):
- """ START and SUCCESS messages are expected to have no useful
- information in the message text, so we display the logfile name for
- these messages, and the message text for other types.
- """
def __init__(self, content_profile, format_profile, err_profile):
super(MessageOrLogFile, self).__init__(content_profile, format_profile)
- self.message_widget = MessageText(content_profile, format_profile)
- self.logfile_widget = LogFile(content_profile, format_profile, err_profile)
+ self._message_widget = MessageText(content_profile, format_profile)
+ self._logfile_widget = LogFile(content_profile, format_profile, err_profile)
def size_request(self, pipeline):
- self.message_widget.size_request(pipeline)
- self.logfile_widget.size_request(pipeline)
+ self._message_widget.size_request(pipeline)
+ self._logfile_widget.size_request(pipeline)
def render(self, message):
# Show the log file only in the main start/success messages
if message.logfile and message.scheduler and \
message.message_type in [MessageType.START, MessageType.SUCCESS]:
- text = self.logfile_widget.render(message)
+ text = self._logfile_widget.render(message)
else:
- text = self.message_widget.render(message)
+ text = self._message_widget.render(message)
return text
@@ -326,27 +326,24 @@ class LogLine(Widget):
message_format: str = None):
super(LogLine, self).__init__(content_profile, format_profile)
- self.columns = []
+ self._columns = []
self._failure_messages = defaultdict(list)
self._context = None
- self.success_profile = success_profile
- self.err_profile = err_profile
- self.detail_profile = detail_profile
- self.indent = ' ' * indent
- self.log_lines = log_lines
- self.message_lines = message_lines
- self.message_format = message_format
+ self._success_profile = success_profile
+ self._err_profile = err_profile
+ self._detail_profile = detail_profile
+ self._indent = ' ' * indent
+ self._log_lines = log_lines
+ self._message_lines = message_lines
- self.space_widget = Space(content_profile, format_profile)
- self.logfile_widget = LogFile(content_profile, format_profile, err_profile)
+ self._space_widget = Space(content_profile, format_profile)
+ self._logfile_widget = LogFile(content_profile, format_profile, err_profile)
if debug:
- self.columns.extend([
+ self._columns.extend([
Debug(content_profile, format_profile)
])
- logfile_format = message_format
-
self.logfile_variable_names = {
"elapsed": TimeCode(content_profile, format_profile, microseconds=False),
"elapsed-us": TimeCode(content_profile, format_profile, microseconds=True),
@@ -356,159 +353,100 @@ class LogLine(Widget):
"action": TypeName(content_profile, format_profile),
"message": MessageOrLogFile(content_profile, format_profile, err_profile)
}
- logfile_tokens = self._parse_logfile_format(logfile_format, content_profile, format_profile)
- self.columns.extend(logfile_tokens)
-
- def _parse_logfile_format(self, format_string, content_profile, format_profile):
- logfile_tokens = []
- while format_string:
- if format_string.startswith("%%"):
- logfile_tokens.append(FixedText("%", content_profile, format_profile))
- format_string = format_string[2:]
- continue
- m = re.search(r"^%\{([^\}]+)\}", format_string)
- if m is not None:
- variable = m.group(1)
- format_string = format_string[m.end(0):]
- if variable not in self.logfile_variable_names:
- raise Exception("'{0}' is not a valid log variable name.".format(variable))
- logfile_tokens.append(self.logfile_variable_names[variable])
- else:
- m = re.search("^[^%]+", format_string)
- if m is not None:
- text = FixedText(m.group(0), content_profile, format_profile)
- format_string = format_string[m.end(0):]
- logfile_tokens.append(text)
- else:
- # No idea what to do now
- raise Exception("'{0}' could not be parsed into a valid logging format.".format(format_string))
- return logfile_tokens
-
- def size_request(self, pipeline):
- for widget in self.columns:
- widget.size_request(pipeline)
-
- self.space_widget.size_request(pipeline)
- self.logfile_widget.size_request(pipeline)
-
- self._context = pipeline.context
-
- def render(self, message):
-
- # Track logfiles for later use
- element_id = message.task_id or message.unique_id
- if message.message_type in ERROR_MESSAGES and element_id is not None:
- plugin = _plugin_lookup(element_id)
- self._failure_messages[plugin].append(message)
-
- return self._render(message)
-
- def _render(self, message):
-
- # Render the column widgets first
- text = ''
- for widget in self.columns:
- text += widget.render(message)
+ logfile_tokens = self._parse_logfile_format(message_format, content_profile, format_profile)
+ self._columns.extend(logfile_tokens)
- text += '\n'
-
- extra_nl = False
-
- # Now add some custom things
- if message.detail:
-
- # Identify frontend messages, we never abbreviate these
- frontend_message = not (message.task_id or message.unique_id)
-
- # Split and truncate message detail down to message_lines lines
- lines = message.detail.splitlines(True)
-
- n_lines = len(lines)
- abbrev = False
- if message.message_type not in ERROR_MESSAGES \
- and not frontend_message and n_lines > self.message_lines:
- abbrev = True
- lines = lines[0:self.message_lines]
- else:
- lines[n_lines - 1] = lines[n_lines - 1].rstrip('\n')
-
- detail = self.indent + self.indent.join(lines)
-
- text += '\n'
- if message.message_type in ERROR_MESSAGES:
- text += self.err_profile.fmt(detail, bold=True)
- else:
- text += self.detail_profile.fmt(detail)
+ # show_pipeline()
+ #
+ # Display a list of elements in the specified format.
+ #
+ # The formatting string is the one currently documented in `bst show`, this
+ # is used in pipeline session headings and also to implement `bst show`.
+ #
+ # Args:
+ # dependencies (list of Element): A list of Element objects
+ # format_: A formatting string, as specified by `bst show`
+ #
+ # Returns:
+ # (str): The formatted list of elements
+ #
+ def show_pipeline(self, dependencies, format_):
+ report = ''
+ p = Profile()
- if abbrev:
- text += self.indent + \
- self.content_profile.fmt('Message contains {} additional lines'
- .format(n_lines - self.message_lines), dim=True)
- text += '\n'
+ for element in dependencies:
+ line = format_
- extra_nl = True
+ full_key, cache_key, dim_keys = element._get_display_key()
- if message.sandbox is not None:
- sandbox = self.indent + 'Sandbox directory: ' + message.sandbox
+ line = p.fmt_subst(line, 'name', element._get_full_name(), fg='blue', bold=True)
+ line = p.fmt_subst(line, 'key', cache_key, fg='yellow', dim=dim_keys)
+ line = p.fmt_subst(line, 'full-key', full_key, fg='yellow', dim=dim_keys)
- text += '\n'
- if message.message_type == MessageType.FAIL:
- text += self.err_profile.fmt(sandbox, bold=True)
+ consistency = element._get_consistency()
+ if consistency == Consistency.INCONSISTENT:
+ line = p.fmt_subst(line, 'state', "no reference", fg='red')
else:
- text += self.detail_profile.fmt(sandbox)
- text += '\n'
- extra_nl = True
-
- if message.scheduler and message.message_type == MessageType.FAIL:
- text += '\n'
+ if element._cached():
+ line = p.fmt_subst(line, 'state', "cached", fg='magenta')
+ elif element._remotely_cached():
+ line = p.fmt_subst(line, 'state', "downloadable", fg='cyan')
+ elif consistency == Consistency.RESOLVED:
+ line = p.fmt_subst(line, 'state', "fetch needed", fg='red')
+ elif element._buildable():
+ line = p.fmt_subst(line, 'state', "buildable", fg='green')
+ else:
+ line = p.fmt_subst(line, 'state', "waiting", fg='blue')
- if self._context is not None and not self._context.log_verbose:
- text += self.indent + self.err_profile.fmt("Log file: ")
- text += self.indent + self.logfile_widget.render(message) + '\n'
- else:
- text += self.indent + self.err_profile.fmt("Printing the last {} lines from log file:"
- .format(self.log_lines)) + '\n'
- text += self.indent + self.logfile_widget.render(message, abbrev=False) + '\n'
- text += self.indent + self.err_profile.fmt("=" * 70) + '\n'
-
- log_content = self.read_last_lines(message.logfile)
- log_content = textwrap.indent(log_content, self.indent)
- text += self.detail_profile.fmt(log_content)
- text += '\n'
- text += self.indent + self.err_profile.fmt("=" * 70) + '\n'
- extra_nl = True
+ # Element configuration
+ if "%{config" in format_:
+ config = _yaml.node_sanitize(element._Element__config)
+ line = p.fmt_subst(
+ line, 'config',
+ yaml.round_trip_dump(config, default_flow_style=False, allow_unicode=True))
- if extra_nl:
- text += '\n'
+ # Variables
+ if "%{vars" in format_:
+ variables = _yaml.node_sanitize(element._Element__variables.variables)
+ line = p.fmt_subst(
+ line, 'vars',
+ yaml.round_trip_dump(variables, default_flow_style=False, allow_unicode=True))
- return text
+ # Environment
+ if "%{env" in format_:
+ environment = _yaml.node_sanitize(element._Element__environment)
+ line = p.fmt_subst(
+ line, 'env',
+ yaml.round_trip_dump(environment, default_flow_style=False, allow_unicode=True))
- def read_last_lines(self, logfile):
- with ExitStack() as stack:
- # mmap handles low-level memory details, allowing for
- # faster searches
- f = stack.enter_context(open(logfile, 'r+'))
- log = stack.enter_context(mmap(f.fileno(), os.path.getsize(f.name)))
+ # Public
+ if "%{public" in format_:
+ environment = _yaml.node_sanitize(element._Element__public)
+ line = p.fmt_subst(
+ line, 'public',
+ yaml.round_trip_dump(environment, default_flow_style=False, allow_unicode=True))
- count = 0
- end = log.size() - 1
+ # Workspaced
+ if "%{workspaced" in format_:
+ line = p.fmt_subst(
+ line, 'workspaced',
+ '(workspaced)' if element._get_workspace() else '', fg='yellow')
- while count < self.log_lines and end >= 0:
- location = log.rfind(b'\n', 0, end)
- count += 1
+ # Workspace-dirs
+ if "%{workspace-dirs" in format_:
+ workspace = element._get_workspace()
+ if workspace is not None:
+ path = workspace.path.replace(os.getenv('HOME', '/root'), '~')
+ line = p.fmt_subst(line, 'workspace-dirs', "Workspace: {}".format(path))
+ else:
+ line = p.fmt_subst(
+ line, 'workspace-dirs', '')
- # If location is -1 (none found), this will print the
- # first character because of the later +1
- end = location
+ report += line + '\n'
- # end+1 is correct whether or not a newline was found at
- # that location. If end is -1 (seek before beginning of file)
- # then we get the first characther. If end is a newline position,
- # we discard it and only want to print the beginning of the next
- # line.
- lines = log[(end + 1):].splitlines()
- return '\n'.join([line.decode('utf-8') for line in lines]).rstrip()
+ return report.rstrip('\n')
+ # print_heading()
#
# A message to be printed at program startup, indicating
# some things about user configuration and BuildStream version
@@ -533,7 +471,7 @@ class LogLine(Widget):
values["Session Start"] = starttime.strftime('%A, %d-%m-%Y at %H:%M:%S')
values["Project"] = "{} ({})".format(project.name, project.directory)
values["Targets"] = ", ".join([t.name for t in pipeline.targets])
- text += self.format_values(values)
+ text += self._format_values(values)
# User configurations
text += '\n'
@@ -550,7 +488,7 @@ class LogLine(Widget):
values["Maximum Build Tasks"] = context.sched_builders
values["Maximum Push Tasks"] = context.sched_pushers
values["Maximum Network Retries"] = context.sched_network_retries
- text += self.format_values(values)
+ text += self._format_values(values)
text += '\n'
# Project Options
@@ -558,12 +496,12 @@ class LogLine(Widget):
project.options.printable_variables(values)
if values:
text += self.content_profile.fmt("Project Options\n", bold=True)
- text += self.format_values(values)
+ text += self._format_values(values)
text += '\n'
# Plugins
- text += self.format_plugins(project._element_factory.loaded_dependencies,
- project._source_factory.loaded_dependencies)
+ text += self._format_plugins(project._element_factory.loaded_dependencies,
+ project._source_factory.loaded_dependencies)
# Pipeline state
text += self.content_profile.fmt("Pipeline\n", bold=True)
@@ -579,7 +517,15 @@ class LogLine(Widget):
if log_file:
click.echo(text, file=log_file, color=False, nl=False)
- # Print queue summaries at the end of a scheduler run
+ # print_summary()
+ #
+ # Print a summary of activities at the end of a session
+ #
+ # Args:
+ # pipeline (Pipeline): The Pipeline
+ # scheduler (Scheduler): The Scheduler
+ # log_file (file): An optional file handle for additional logging
+ # styling (bool): Whether to enable ansi escape codes in the output
#
def print_summary(self, pipeline, scheduler, log_file, styling=False):
@@ -597,7 +543,7 @@ class LogLine(Widget):
for element, messages in sorted(self._failure_messages.items(), key=lambda x: x[0].name):
values[element.name] = ''.join(self._render(v) for v in messages)
- text += self.format_values(values, style_value=False)
+ text += self._format_values(values, style_value=False)
text += self.content_profile.fmt("Pipeline Summary\n", bold=True)
values = OrderedDict()
@@ -623,7 +569,7 @@ class LogLine(Widget):
failed_align = ' ' * (failed_maxlen - len(failed))
status_text = self.content_profile.fmt("processed ") + \
- self.success_profile.fmt(processed) + \
+ self._success_profile.fmt(processed) + \
self.format_profile.fmt(', ') + processed_align
status_text += self.content_profile.fmt("skipped ") + \
@@ -631,16 +577,172 @@ class LogLine(Widget):
self.format_profile.fmt(', ') + skipped_align
status_text += self.content_profile.fmt("failed ") + \
- self.err_profile.fmt(failed) + ' ' + failed_align
+ self._err_profile.fmt(failed) + ' ' + failed_align
values["{} Queue".format(queue.action_name)] = status_text
- text += self.format_values(values, style_value=False)
+ text += self._format_values(values, style_value=False)
click.echo(text, color=styling, nl=False, err=True)
if log_file:
click.echo(text, file=log_file, color=False, nl=False)
- def format_plugins(self, element_plugins, source_plugins):
+ ###################################################
+ # Widget Abstract Methods #
+ ###################################################
+ def size_request(self, pipeline):
+ for widget in self._columns:
+ widget.size_request(pipeline)
+
+ self._space_widget.size_request(pipeline)
+ self._logfile_widget.size_request(pipeline)
+
+ self._context = pipeline.context
+
+ def render(self, message):
+
+ # Track logfiles for later use
+ element_id = message.task_id or message.unique_id
+ if message.message_type in ERROR_MESSAGES and element_id is not None:
+ plugin = _plugin_lookup(element_id)
+ self._failure_messages[plugin].append(message)
+
+ return self._render(message)
+
+ ###################################################
+ # Private Methods #
+ ###################################################
+ def _parse_logfile_format(self, format_string, content_profile, format_profile):
+ logfile_tokens = []
+ while format_string:
+ if format_string.startswith("%%"):
+ logfile_tokens.append(FixedText("%", content_profile, format_profile))
+ format_string = format_string[2:]
+ continue
+ m = re.search(r"^%\{([^\}]+)\}", format_string)
+ if m is not None:
+ variable = m.group(1)
+ format_string = format_string[m.end(0):]
+ if variable not in self.logfile_variable_names:
+ raise Exception("'{0}' is not a valid log variable name.".format(variable))
+ logfile_tokens.append(self.logfile_variable_names[variable])
+ else:
+ m = re.search("^[^%]+", format_string)
+ if m is not None:
+ text = FixedText(m.group(0), content_profile, format_profile)
+ format_string = format_string[m.end(0):]
+ logfile_tokens.append(text)
+ else:
+ # No idea what to do now
+ raise Exception("'{0}' could not be parsed into a valid logging format.".format(format_string))
+ return logfile_tokens
+
+ def _render(self, message):
+
+ # Render the column widgets first
+ text = ''
+ for widget in self._columns:
+ text += widget.render(message)
+
+ text += '\n'
+
+ extra_nl = False
+
+ # Now add some custom things
+ if message.detail:
+
+ # Identify frontend messages, we never abbreviate these
+ frontend_message = not (message.task_id or message.unique_id)
+
+ # Split and truncate message detail down to message_lines lines
+ lines = message.detail.splitlines(True)
+
+ n_lines = len(lines)
+ abbrev = False
+ if message.message_type not in ERROR_MESSAGES \
+ and not frontend_message and n_lines > self._message_lines:
+ abbrev = True
+ lines = lines[0:self._message_lines]
+ else:
+ lines[n_lines - 1] = lines[n_lines - 1].rstrip('\n')
+
+ detail = self._indent + self._indent.join(lines)
+
+ text += '\n'
+ if message.message_type in ERROR_MESSAGES:
+ text += self._err_profile.fmt(detail, bold=True)
+ else:
+ text += self._detail_profile.fmt(detail)
+
+ if abbrev:
+ text += self._indent + \
+ self.content_profile.fmt('Message contains {} additional lines'
+ .format(n_lines - self._message_lines), dim=True)
+ text += '\n'
+
+ extra_nl = True
+
+ if message.sandbox is not None:
+ sandbox = self._indent + 'Sandbox directory: ' + message.sandbox
+
+ text += '\n'
+ if message.message_type == MessageType.FAIL:
+ text += self._err_profile.fmt(sandbox, bold=True)
+ else:
+ text += self._detail_profile.fmt(sandbox)
+ text += '\n'
+ extra_nl = True
+
+ if message.scheduler and message.message_type == MessageType.FAIL:
+ text += '\n'
+
+ if self._context is not None and not self._context.log_verbose:
+ text += self._indent + self._err_profile.fmt("Log file: ")
+ text += self._indent + self._logfile_widget.render(message) + '\n'
+ else:
+ text += self._indent + self._err_profile.fmt("Printing the last {} lines from log file:"
+ .format(self._log_lines)) + '\n'
+ text += self._indent + self._logfile_widget.render(message, abbrev=False) + '\n'
+ text += self._indent + self._err_profile.fmt("=" * 70) + '\n'
+
+ log_content = self._read_last_lines(message.logfile)
+ log_content = textwrap.indent(log_content, self._indent)
+ text += self._detail_profile.fmt(log_content)
+ text += '\n'
+ text += self._indent + self._err_profile.fmt("=" * 70) + '\n'
+ extra_nl = True
+
+ if extra_nl:
+ text += '\n'
+
+ return text
+
+ def _read_last_lines(self, logfile):
+ with ExitStack() as stack:
+ # mmap handles low-level memory details, allowing for
+ # faster searches
+ f = stack.enter_context(open(logfile, 'r+'))
+ log = stack.enter_context(mmap(f.fileno(), os.path.getsize(f.name)))
+
+ count = 0
+ end = log.size() - 1
+
+ while count < self._log_lines and end >= 0:
+ location = log.rfind(b'\n', 0, end)
+ count += 1
+
+ # If location is -1 (none found), this will print the
+ # first character because of the later +1
+ end = location
+
+ # end+1 is correct whether or not a newline was found at
+ # that location. If end is -1 (seek before beginning of file)
+ # then we get the first characther. If end is a newline position,
+ # we discard it and only want to print the beginning of the next
+ # line.
+ lines = log[(end + 1):].splitlines()
+ return '\n'.join([line.decode('utf-8') for line in lines]).rstrip()
+
+ def _format_plugins(self, element_plugins, source_plugins):
text = ""
if not (element_plugins or source_plugins):
@@ -662,7 +764,19 @@ class LogLine(Widget):
return text
- def format_values(self, values, style_value=True):
+ # _format_values()
+ #
+ # Formats an indented dictionary of titles / values, ensuring
+ # the values are aligned.
+ #
+ # Args:
+ # values: A dictionary, usually an OrderedDict()
+ # style_value: Whether to use the content profile for the values
+ #
+ # Returns:
+ # (str): The formatted values
+ #
+ def _format_values(self, values, style_value=True):
text = ''
max_key_len = 0
for key, value in values.items():
@@ -671,7 +785,7 @@ class LogLine(Widget):
for key, value in values.items():
if isinstance(value, str) and '\n' in value:
text += self.format_profile.fmt(" {}:\n".format(key))
- text += textwrap.indent(value, self.indent)
+ text += textwrap.indent(value, self._indent)
continue
text += self.format_profile.fmt(" {}: {}".format(key, ' ' * (max_key_len - len(key))))
@@ -682,79 +796,3 @@ class LogLine(Widget):
text += '\n'
return text
-
- def show_pipeline(self, dependencies, format_):
- report = ''
- p = Profile()
-
- for element in dependencies:
- line = format_
-
- full_key, cache_key, dim_keys = element._get_display_key()
-
- line = p.fmt_subst(line, 'name', element._get_full_name(), fg='blue', bold=True)
- line = p.fmt_subst(line, 'key', cache_key, fg='yellow', dim=dim_keys)
- line = p.fmt_subst(line, 'full-key', full_key, fg='yellow', dim=dim_keys)
-
- consistency = element._get_consistency()
- if consistency == Consistency.INCONSISTENT:
- line = p.fmt_subst(line, 'state', "no reference", fg='red')
- else:
- if element._cached():
- line = p.fmt_subst(line, 'state', "cached", fg='magenta')
- elif element._remotely_cached():
- line = p.fmt_subst(line, 'state', "downloadable", fg='cyan')
- elif consistency == Consistency.RESOLVED:
- line = p.fmt_subst(line, 'state', "fetch needed", fg='red')
- elif element._buildable():
- line = p.fmt_subst(line, 'state', "buildable", fg='green')
- else:
- line = p.fmt_subst(line, 'state', "waiting", fg='blue')
-
- # Element configuration
- if "%{config" in format_:
- config = _yaml.node_sanitize(element._Element__config)
- line = p.fmt_subst(
- line, 'config',
- yaml.round_trip_dump(config, default_flow_style=False, allow_unicode=True))
-
- # Variables
- if "%{vars" in format_:
- variables = _yaml.node_sanitize(element._Element__variables.variables)
- line = p.fmt_subst(
- line, 'vars',
- yaml.round_trip_dump(variables, default_flow_style=False, allow_unicode=True))
-
- # Environment
- if "%{env" in format_:
- environment = _yaml.node_sanitize(element._Element__environment)
- line = p.fmt_subst(
- line, 'env',
- yaml.round_trip_dump(environment, default_flow_style=False, allow_unicode=True))
-
- # Public
- if "%{public" in format_:
- environment = _yaml.node_sanitize(element._Element__public)
- line = p.fmt_subst(
- line, 'public',
- yaml.round_trip_dump(environment, default_flow_style=False, allow_unicode=True))
-
- # Workspaced
- if "%{workspaced" in format_:
- line = p.fmt_subst(
- line, 'workspaced',
- '(workspaced)' if element._get_workspace() else '', fg='yellow')
-
- # Workspace-dirs
- if "%{workspace-dirs" in format_:
- workspace = element._get_workspace()
- if workspace is not None:
- path = workspace.path.replace(os.getenv('HOME', '/root'), '~')
- line = p.fmt_subst(line, 'workspace-dirs', "Workspace: {}".format(path))
- else:
- line = p.fmt_subst(
- line, 'workspace-dirs', '')
-
- report += line + '\n'
-
- return report.rstrip('\n')