patman: Allow running a tool and returning the full result

Add a new function which returns the entire result from running a tool,
not just stdout. Update Run() to use this and to return stdout on error,
if stderr is empty, since some unfortunate tools write their error
output to stdout rather than stderr.

Move building of the PATH to a separate function.

Make the exception catching more specific, to catch just ValueError, since
broad exceptions are a pain to debug.

Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass
2022-01-09 20:13:40 -07:00
parent 8bc78b73fb
commit ade5327655

View File

@@ -313,6 +313,70 @@ def GetTargetCompileTool(name, cross_compile=None):
target_name = name
return target_name, extra_args
def get_env_with_path():
"""Get an updated environment with the PATH variable set correctly
If there are any search paths set, these need to come first in the PATH so
that these override any other version of the tools.
Returns:
dict: New environment with PATH updated, or None if there are not search
paths
"""
if tool_search_paths:
env = dict(os.environ)
env['PATH'] = ':'.join(tool_search_paths) + ':' + env['PATH']
return env
def run_result(name, *args, **kwargs):
"""Run a tool with some arguments
This runs a 'tool', which is a program used by binman to process files and
perhaps produce some output. Tools can be located on the PATH or in a
search path.
Args:
name: Command name to run
args: Arguments to the tool
for_host: True to resolve the command to the version for the host
for_target: False to run the command as-is, without resolving it
to the version for the compile target
raise_on_error: Raise an error if the command fails (True by default)
Returns:
CommandResult object
"""
try:
binary = kwargs.get('binary')
for_host = kwargs.get('for_host', False)
for_target = kwargs.get('for_target', not for_host)
raise_on_error = kwargs.get('raise_on_error', True)
env = get_env_with_path()
if for_target:
name, extra_args = GetTargetCompileTool(name)
args = tuple(extra_args) + args
elif for_host:
name, extra_args = GetHostCompileTool(name)
args = tuple(extra_args) + args
name = os.path.expanduser(name) # Expand paths containing ~
all_args = (name,) + args
result = command.RunPipe([all_args], capture=True, capture_stderr=True,
env=env, raise_on_error=False, binary=binary)
if result.return_code:
if raise_on_error:
raise ValueError("Error %d running '%s': %s" %
(result.return_code,' '.join(all_args),
result.stderr or result.stdout))
return result
except ValueError:
if env and not PathHasFile(env['PATH'], name):
msg = "Please install tool '%s'" % name
package = packages.get(name)
if package:
msg += " (e.g. from package '%s')" % package
raise ValueError(msg)
raise
def Run(name, *args, **kwargs):
"""Run a tool with some arguments
@@ -330,37 +394,9 @@ def Run(name, *args, **kwargs):
Returns:
CommandResult object
"""
try:
binary = kwargs.get('binary')
for_host = kwargs.get('for_host', False)
for_target = kwargs.get('for_target', not for_host)
env = None
if tool_search_paths:
env = dict(os.environ)
env['PATH'] = ':'.join(tool_search_paths) + ':' + env['PATH']
if for_target:
name, extra_args = GetTargetCompileTool(name)
args = tuple(extra_args) + args
elif for_host:
name, extra_args = GetHostCompileTool(name)
args = tuple(extra_args) + args
name = os.path.expanduser(name) # Expand paths containing ~
all_args = (name,) + args
result = command.RunPipe([all_args], capture=True, capture_stderr=True,
env=env, raise_on_error=False, binary=binary)
if result.return_code:
raise ValueError("Error %d running '%s': %s" %
(result.return_code,' '.join(all_args),
result.stderr))
result = run_result(name, *args, **kwargs)
if result is not None:
return result.stdout
except:
if env and not PathHasFile(env['PATH'], name):
msg = "Please install tool '%s'" % name
package = packages.get(name)
if package:
msg += " (e.g. from package '%s')" % package
raise ValueError(msg)
raise
def Filename(fname):
"""Resolve a file path to an absolute path.