[Scons-users] Printing after command

Eric Lunderberg eric.lunderberg at gmail.com
Tue Jan 3 17:30:26 EST 2017


I am attempting to improve the readability of the messages being printed to
screen.  I've used the *COMSTR variables before to customize what gets
printed before a command is run.  I would like to add a message that gets
printed after the command as well, summarizing the results of the command
(i.e. ok, warning, or error).

With make, I can do this by printing a before-run status message, running
the command with the output piped to a file, printing an after-run status
message, then printing the contents of the piped file.  The overall effect
is shown in this gif <https://i.stack.imgur.com/ndiin.gif>.  This way, I
can visually distinguish which file produced warning and error messages,
especially with the different colors for each.  I haven't found a way to
replicate these status messages with scons.

I can get fairly close to a solution by replacing env['SPAWN'] in the
environment.  From there, I can run the command, printing before and after
running the command.  There are two main difficulties that I ran into.
First, the spawn function is passed only the command to be run, and not the
description of the command, as formed from the comstr.  As far as I can
tell, that information is only present in the SCons.Action._ActionAction.

I can get a little bit closer by also replacing the command action (CXXCOM,
SHCXXCOM, etc) with a custom function.  That custom function can generate
the string to be printed, based on the appropriate COMSTR.  It can run the
command, using the custom SPAWN function to grab the output of the command,
then print it afterward.

However, while replacing env['CXXCOM'] allows me to call my custom
function, the COMSTR is still being printed twice.  As far as I can tell,
this is done in the action defined in Defaults.py, before control ever gets
passed to my function.  I would like some way to silence this printing, but
cannot find a way to do so.  As it stands, my best attempt to reproduce the
behavior from the makefile is shown in this gif
<http://i.imgur.com/ITE8ber.gif>.  Note that the COMSTR has been printed
twice.

The relevant parts of the SConstruct in order to produce this behavior are
shown below.  Any advice on fixing the double-printing would be most
appreciated.

import sys

class BufferSpawn(object):
    def __init__(self):
        self.stdout = ''

    def __call__(self, sh, escape, cmd, args, spawnenv):
        asciienv = {key:str(value) for key,value in spawnenv.items()}

        # Call a subprocess, grabbing all output
        p = subprocess.Popen(
            ' '.join(args),
            shell=True,
            env=asciienv,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT,
            universal_newlines=True)
        stdout,stderr = p.communicate()

        self.stdout = stdout

        return p.returncode

class CommandWrapper(object):
    _null = SCons.Action._null

    def __init__(self, env, com, comstr):
        self.overrides = {com:env[com],
                          comstr:env[comstr],
                          }
        self.action = SCons.Action.Action('$'+com, '$'+comstr)
        self.pad_to = 50

    def __call__(self, target, source, env,
                               exitstatfunc=_null,
                               presub=_null,
                               show=_null,
                               execute=_null,
                               chdir=_null,
                               executor=None):

        # Generate the environment for the subordinate action
        overrides = self.overrides.copy()
        spawn = BufferSpawn()
        overrides['SPAWN'] = spawn
        env = env.Override(overrides)

        # Generate the status message to be printed
        try:
            to_print = self.action.strfunction(target, source, env,
executor)
        except TypeError:
            to_print = self.action.strfunction(target, source, env)

        to_print = to_print.ljust(self.pad_to)

        # Print the before-command status
        print to_print + '\r',
        sys.stdout.flush()

        # Run the command, without printing anything.
        show = False
        retval = self.action(target, source, env, exitstatfunc,
                             presub, show, execute, chdir, executor)

        # Figure out the change to the status message
        if retval:
            print_result = '[ERROR]'
        elif spawn.stdout:
            print_result = '[WARNING]'
        else:
            print_result = '[OK]'

        # Print the after-command status, and the stdout, if any
        print to_print + print_result
        if spawn.stdout:
            print spawn.stdout
        sys.stdout.flush()

env['CXXCOMSTR'] = 'Compiling C++ object $TARGETS'
env['CXXCOM'] = CommandWrapper(env, 'CXXCOM','CXXCOMSTR')
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://pairlist4.pair.net/pipermail/scons-users/attachments/20170103/bec6e01b/attachment.html>


More information about the Scons-users mailing list