Skip to content
Snippets Groups Projects
Commit 1d085568 authored by Masahiro Yamada's avatar Masahiro Yamada
Browse files

tools: moveconfig: display log atomically in more readable format


Before this commit, the log was displayed in the format:

<defconfig_name>   : <action1>
<defconfig_name>   : <action2>
<defconfig_name>   : <action3>

When we move multiple CONFIGs at the same time, we see as many
<defconfig_name> strings as actions for every defconfig, which is
redundant information.

Moreover, since normal log and error log are displayed separately,
Messages from different threads could be mixed, like this:

<foo>              : <action1>
<foo>              : <action2>
<bar>              : <action1>
<bar>              : <action2>
<foo>              : <error_log>

This commit makes sure to call "print" once a defconfig, which
enables atomic logging for each defconfig.  It also makes it
possible to refactor the log format as follows:

<foo_defconfig>
    <action1>
    <action2>
    <error_log>

<bar_defconfig>
    <action1>
    <action2>

Signed-off-by: default avatarMasahiro Yamada <yamada.masahiro@socionext.com>
Reviewed-by: default avatarJoe Hershberger <joe.hershberger@ni.com>
parent 522e8dcb
No related branches found
No related tags found
No related merge requests found
...@@ -30,13 +30,17 @@ The tool walks through all the defconfig files and move the given CONFIGs. ...@@ -30,13 +30,17 @@ The tool walks through all the defconfig files and move the given CONFIGs.
The log is also displayed on the terminal. The log is also displayed on the terminal.
Each line is printed in the format The log is printed for each defconfig as follows:
<defconfig_name> : <action>
<defconfig_name> is the name of the defconfig <defconfig_name>
(without the suffix _defconfig). <action1>
<action2>
<action3>
...
<action> shows what the tool did for that defconfig. <defconfig_name> is the name of the defconfig.
<action*> shows what the tool did for that defconfig.
It looks like one of the followings: It looks like one of the followings:
- Move 'CONFIG_... ' - Move 'CONFIG_... '
...@@ -249,15 +253,13 @@ def get_make_cmd(): ...@@ -249,15 +253,13 @@ def get_make_cmd():
def color_text(color_enabled, color, string): def color_text(color_enabled, color, string):
"""Return colored string.""" """Return colored string."""
if color_enabled: if color_enabled:
return '\033[' + color + 'm' + string + '\033[0m' # LF should not be surrounded by the escape sequence.
# Otherwise, additional whitespace or line-feed might be printed.
return '\n'.join([ '\033[' + color + 'm' + s + '\033[0m' if s else ''
for s in string.split('\n') ])
else: else:
return string return string
def log_msg(color_enabled, color, defconfig, msg):
"""Return the formated line for the log."""
return defconfig[:-len('_defconfig')].ljust(37) + ': ' + \
color_text(color_enabled, color, msg) + '\n'
def update_cross_compile(color_enabled): def update_cross_compile(color_enabled):
"""Update per-arch CROSS_COMPILE via environment variables """Update per-arch CROSS_COMPILE via environment variables
...@@ -483,7 +485,7 @@ class KconfigParser: ...@@ -483,7 +485,7 @@ class KconfigParser:
return (ACTION_MOVE, new_val) return (ACTION_MOVE, new_val)
def update_dotconfig(self, defconfig): def update_dotconfig(self):
"""Parse files for the config options and update the .config. """Parse files for the config options and update the .config.
This function parses the generated .config and include/autoconf.mk This function parses the generated .config and include/autoconf.mk
...@@ -526,7 +528,7 @@ class KconfigParser: ...@@ -526,7 +528,7 @@ class KconfigParser:
else: else:
sys.exit("Internal Error. This should not happen.") sys.exit("Internal Error. This should not happen.")
log += log_msg(self.options.color, log_color, defconfig, actlog) log += color_text(self.options.color, log_color, actlog) + '\n'
with open(self.dotconfig, 'a') as f: with open(self.dotconfig, 'a') as f:
for (action, value) in results: for (action, value) in results:
...@@ -602,6 +604,7 @@ class Slot: ...@@ -602,6 +604,7 @@ class Slot:
stderr=subprocess.PIPE) stderr=subprocess.PIPE)
self.defconfig = defconfig self.defconfig = defconfig
self.state = STATE_DEFCONFIG self.state = STATE_DEFCONFIG
self.log = ''
return True return True
def poll(self): def poll(self):
...@@ -624,14 +627,12 @@ class Slot: ...@@ -624,14 +627,12 @@ class Slot:
return False return False
if self.ps.poll() != 0: if self.ps.poll() != 0:
print >> sys.stderr, log_msg(self.options.color, COLOR_LIGHT_RED, self.log += color_text(self.options.color, COLOR_LIGHT_RED,
self.defconfig, "Failed to process."), "Failed to process.\n")
if self.options.verbose: if self.options.verbose:
print >> sys.stderr, color_text(self.options.color, self.log += color_text(self.options.color, COLOR_LIGHT_CYAN,
COLOR_LIGHT_CYAN, self.ps.stderr.read())
self.ps.stderr.read()) self.show_log(sys.stderr)
self.progress.inc()
self.progress.show()
if self.options.exit_on_error: if self.options.exit_on_error:
sys.exit("Exit on error.") sys.exit("Exit on error.")
# If --exit-on-error flag is not set, skip this board and continue. # If --exit-on-error flag is not set, skip this board and continue.
...@@ -641,7 +642,7 @@ class Slot: ...@@ -641,7 +642,7 @@ class Slot:
return True return True
if self.state == STATE_AUTOCONF: if self.state == STATE_AUTOCONF:
self.log = self.parser.update_dotconfig(self.defconfig) self.log += self.parser.update_dotconfig()
"""Save off the defconfig in a consistent way""" """Save off the defconfig in a consistent way"""
cmd = list(self.make_cmd) cmd = list(self.make_cmd)
...@@ -655,21 +656,15 @@ class Slot: ...@@ -655,21 +656,15 @@ class Slot:
if not self.options.dry_run: if not self.options.dry_run:
shutil.move(os.path.join(self.build_dir, 'defconfig'), shutil.move(os.path.join(self.build_dir, 'defconfig'),
os.path.join('configs', self.defconfig)) os.path.join('configs', self.defconfig))
# Some threads are running in parallel. self.show_log()
# Print log in one shot to not mix up logs from different threads.
print self.log,
self.progress.inc()
self.progress.show()
self.state = STATE_IDLE self.state = STATE_IDLE
return True return True
self.cross_compile = self.parser.get_cross_compile() self.cross_compile = self.parser.get_cross_compile()
if self.cross_compile is None: if self.cross_compile is None:
print >> sys.stderr, log_msg(self.options.color, COLOR_YELLOW, self.log += color_text(self.options.color, COLOR_YELLOW,
self.defconfig, "Compiler is missing. Do nothing.\n")
"Compiler is missing. Do nothing."), self.show_log(sys.stderr)
self.progress.inc()
self.progress.show()
if self.options.exit_on_error: if self.options.exit_on_error:
sys.exit("Exit on error.") sys.exit("Exit on error.")
# If --exit-on-error flag is not set, skip this board and continue. # If --exit-on-error flag is not set, skip this board and continue.
...@@ -688,6 +683,22 @@ class Slot: ...@@ -688,6 +683,22 @@ class Slot:
self.state = STATE_AUTOCONF self.state = STATE_AUTOCONF
return False return False
def show_log(self, file=sys.stdout):
"""Display log along with progress.
Arguments:
file: A file object to which the log string is sent.
"""
# output at least 30 characters to hide the "* defconfigs out of *".
log = self.defconfig.ljust(30) + '\n'
log += '\n'.join([ ' ' + s for s in self.log.split('\n') ])
# Some threads are running in parallel.
# Print log atomically to not mix up logs from different threads.
print >> file, log
self.progress.inc()
self.progress.show()
def get_failed_boards(self): def get_failed_boards(self):
"""Returns a list of failed boards (defconfigs) in this slot. """Returns a list of failed boards (defconfigs) in this slot.
""" """
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment