diff options
author | Tristan Van Berkom <tristan.vanberkom@codethink.co.uk> | 2018-04-15 20:06:17 +0900 |
---|---|---|
committer | Tristan Van Berkom <tristan.vanberkom@codethink.co.uk> | 2018-04-15 20:10:01 +0900 |
commit | e769beca15b333f0feafc7e67a9437b3f988c518 (patch) | |
tree | e375a9b115bfe63563181646195ba74792c6f551 /buildstream/_frontend | |
parent | 219c7d2998f3259de1beff4f7d74f1a4423321c4 (diff) | |
download | buildstream-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.py | 576 |
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') |