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: Masahiro Yamada <yamada.masahiro@socionext.com>
Reviewed-by: Joe Hershberger <joe.hershberger@ni.com>
This commit is contained in:
Masahiro Yamada 2016-05-19 15:52:02 +09:00
parent 522e8dcb4c
commit 1d085568b3

View File

@ -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():
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:
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:
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:
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:
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:
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:
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:
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.
""" """