Fix 'meson subprojects foreach' when command returns non-zero exit code

The 'output' field of the subprocess.CalledProcessError exception is
valid only when subprocess.check_output() is called, trying to access it
after calling subprocess.check_call() results in an unwanted exception
when commands return non-zero exit code, e.g.:

-----------------------------------------------------------------------
$ meson subprojects foreach false
Executing command in ./subprojects/sqlite-amalgamation-3250100
  -> Not downloaded yet
Executing command in ./subprojects/gstreamer
Traceback (most recent call last):
  File "/home/ao2/meson/meson/mesonbuild/msubprojects.py", line 177, in foreach
    subprocess.check_call([options.command] + options.args, cwd=repo_dir)
  File "/usr/lib/python3.7/subprocess.py", line 363, in check_call
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['false']' returned non-zero exit status 1.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/ao2/meson/meson/mesonbuild/mesonmain.py", line 129, in run
    return options.run_func(options)
  File "/home/ao2/meson/meson/mesonbuild/msubprojects.py", line 248, in run
    options.subprojects_func(wrap, repo_dir, options)
  File "/home/ao2/meson/meson/mesonbuild/msubprojects.py", line 180, in foreach
    out = e.output.decode().strip()
AttributeError: 'NoneType' object has no attribute 'decode'
-----------------------------------------------------------------------

Use subprocess.check_output() instead and behave more like git commands
in handling stderr.

This makes it possible to actually run commands on all subprojects
allowing them to fail on some subprojects and succeed on others.

Also catch the case of missing commands and print an error message in
this case as well.
pull/6301/head
Antonio Ospite 5 years ago committed by Jussi Pakkanen
parent 63bea704dd
commit c616686d5d
  1. 14
      mesonbuild/msubprojects.py

@ -178,11 +178,17 @@ def foreach(wrap, repo_dir, options):
mlog.log(' -> Not downloaded yet')
return
try:
subprocess.check_call([options.command] + options.args, cwd=repo_dir)
mlog.log('')
out = subprocess.check_output([options.command] + options.args,
stderr=subprocess.STDOUT,
cwd=repo_dir).decode()
mlog.log(out, end='')
except subprocess.CalledProcessError as e:
out = e.output.decode().strip()
mlog.log(' -> ', mlog.red(out))
err_message = "Command '%s' returned non-zero exit status %d." % (" ".join(e.cmd), e.returncode)
out = e.output.decode()
mlog.log(' -> ', mlog.red(err_message))
mlog.log(out, end='')
except Exception as e:
mlog.log(' -> ', mlog.red(str(e)))
def add_common_arguments(p):
p.add_argument('--sourcedir', default='.',

Loading…
Cancel
Save