Fix bug with invalid process's "return code" when PlatformIO has internal error

This commit is contained in:
Ivan Kravets
2015-02-19 22:02:50 +02:00
parent 1fc6b222ec
commit 2d53d2100d
7 changed files with 48 additions and 22 deletions

View File

@ -31,6 +31,8 @@ Release History
* Fixed compiling error if space is in user's folder (`issue #56 <https://github.com/ivankravets/platformio/issues/56>`_) * Fixed compiling error if space is in user's folder (`issue #56 <https://github.com/ivankravets/platformio/issues/56>`_)
* Fixed `AttributeError: 'module' object has no attribute 'disable_warnings'` * Fixed `AttributeError: 'module' object has no attribute 'disable_warnings'`
when a version of `requests` package is less then 2.4.0 when a version of `requests` package is less then 2.4.0
* Fixed bug with invalid process's "return code" when PlatformIO has internal
error (`issue #81 <https://github.com/ivankravets/platformio/issues/81>`_)
0.10.2 (2015-01-06) 0.10.2 (2015-01-06)

View File

@ -8,8 +8,7 @@ from traceback import format_exc
import click import click
from platformio import __version__, maintenance from platformio import __version__, exception, maintenance
from platformio.exception import PlatformioException, UnknownCLICommand
from platformio.util import get_source_dir from platformio.util import get_source_dir
@ -31,7 +30,7 @@ class PlatformioCLI(click.MultiCommand): # pylint: disable=R0904
mod = __import__("platformio.commands." + name, mod = __import__("platformio.commands." + name,
None, None, ["cli"]) None, None, ["cli"])
except ImportError: except ImportError:
raise UnknownCLICommand(name) raise exception.UnknownCLICommand(name)
return mod.cli return mod.cli
@ -52,12 +51,13 @@ def main():
try: try:
cli(None) cli(None)
except Exception as e: # pylint: disable=W0703 except Exception as e: # pylint: disable=W0703
maintenance.on_platformio_exception(e) if not isinstance(e, exception.ReturnErrorCode):
if isinstance(e, PlatformioException): maintenance.on_platformio_exception(e)
click.echo("Error: " + str(e), err=True) if isinstance(e, exception.PlatformioException):
sys_exit(1) click.echo("Error: " + str(e), err=True)
else: else:
print format_exc() click.echo(format_exc(), err=True)
sys_exit(1)
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -36,6 +36,7 @@ def cli(ctx, environment, target, upload_port):
getmtime(_pioenvs_dir)): getmtime(_pioenvs_dir)):
rmtree(_pioenvs_dir) rmtree(_pioenvs_dir)
found_error = False
_first_done = False _first_done = False
for section in config.sections(): for section in config.sections():
# skip main configuration section # skip main configuration section
@ -56,9 +57,13 @@ def cli(ctx, environment, target, upload_port):
if _first_done: if _first_done:
click.echo() click.echo()
process_environment(ctx, envname, options, target, upload_port) if not process_environment(ctx, envname, options, target, upload_port):
found_error = True
_first_done = True _first_done = True
if found_error:
raise exception.ReturnErrorCode()
def process_environment(ctx, name, options, targets, upload_port): def process_environment(ctx, name, options, targets, upload_port):
terminal_width, _ = click.get_terminal_size() terminal_width, _ = click.get_terminal_size()
@ -72,8 +77,8 @@ def process_environment(ctx, name, options, targets, upload_port):
click.secho("-" * terminal_width, bold=True) click.secho("-" * terminal_width, bold=True)
result = _run_environment(ctx, name, options, targets, upload_port) result = _run_environment(ctx, name, options, targets, upload_port)
is_error = "error" in result['err'].lower()
is_error = result['returncode'] != 0
summary_text = " Took %.2f seconds " % (time() - start_time) summary_text = " Took %.2f seconds " % (time() - start_time)
half_line = "=" * ((terminal_width - len(summary_text) - 10) / 2) half_line = "=" * ((terminal_width - len(summary_text) - 10) / 2)
click.echo("%s [%s]%s%s" % ( click.echo("%s [%s]%s%s" % (
@ -84,6 +89,8 @@ def process_environment(ctx, name, options, targets, upload_port):
half_line half_line
), err=is_error) ), err=is_error)
return not is_error
def _run_environment(ctx, name, options, targets, upload_port): def _run_environment(ctx, name, options, targets, upload_port):
variables = ["PIOENV=" + name] variables = ["PIOENV=" + name]

View File

@ -13,6 +13,10 @@ class PlatformioException(Exception):
return Exception.__str__(self) return Exception.__str__(self)
class ReturnErrorCode(PlatformioException):
pass
class AbortedByUser(PlatformioException): class AbortedByUser(PlatformioException):
MESSAGE = "Aborted by user" MESSAGE = "Aborted by user"

View File

@ -1,6 +1,7 @@
# Copyright (C) Ivan Kravets <me@ikravets.com> # Copyright (C) Ivan Kravets <me@ikravets.com>
# See LICENSE for details. # See LICENSE for details.
import re
from imp import load_source from imp import load_source
from os import listdir from os import listdir
from os.path import isdir, isfile, join from os.path import isdir, isfile, join
@ -76,6 +77,10 @@ class PlatformFactory(object):
class BasePlatform(object): class BasePlatform(object):
PACKAGES = {} PACKAGES = {}
LINE_ERROR_RE = re.compile(r"(\s+error|error[:\s]+)", re.I)
def __init__(self):
self._found_error = False
def get_name(self): def get_name(self):
return self.__class__.__name__[:-8].lower() return self.__class__.__name__[:-8].lower()
@ -214,6 +219,7 @@ class BasePlatform(object):
variables.append( variables.append(
"PIOPACKAGE_%s=%s" % (options['alias'].upper(), name)) "PIOPACKAGE_%s=%s" % (options['alias'].upper(), name))
self._found_error = False
try: try:
result = util.exec_command( result = util.exec_command(
[ [
@ -227,9 +233,10 @@ class BasePlatform(object):
except OSError: except OSError:
raise exception.SConsNotInstalled() raise exception.SConsNotInstalled()
return self.after_run(result) assert "returncode" in result
if self._found_error:
result['returncode'] = 1
def after_run(self, result): # pylint: disable=R0201
return result return result
def on_run_out(self, line): # pylint: disable=R0201 def on_run_out(self, line): # pylint: disable=R0201
@ -239,5 +246,7 @@ class BasePlatform(object):
click.secho(line, fg=fg) click.secho(line, fg=fg)
def on_run_err(self, line): # pylint: disable=R0201 def on_run_err(self, line): # pylint: disable=R0201
click.secho(line, err=True, is_error = self.LINE_ERROR_RE.search(line) is not None
fg="red" if "error" in line.lower() else "yellow") if is_error:
self._found_error = True
click.secho(line, err=True, fg="red" if is_error else "yellow")

View File

@ -117,7 +117,12 @@ def change_filemtime(path, time):
def exec_command(*args, **kwargs): def exec_command(*args, **kwargs):
result = {"out": None, "err": None} result = {
"out": None,
"err": None,
"returncode": None
}
default = dict( default = dict(
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, stderr=subprocess.PIPE,
@ -129,6 +134,7 @@ def exec_command(*args, **kwargs):
p = subprocess.Popen(*args, **kwargs) p = subprocess.Popen(*args, **kwargs)
try: try:
result['out'], result['err'] = p.communicate() result['out'], result['err'] = p.communicate()
result['returncode'] = p.returncode
except KeyboardInterrupt: except KeyboardInterrupt:
for s in ("stdout", "stderr"): for s in ("stdout", "stderr"):
if isinstance(kwargs[s], AsyncPipe): if isinstance(kwargs[s], AsyncPipe):
@ -141,9 +147,8 @@ def exec_command(*args, **kwargs):
result[s[3:]] = "\n".join(kwargs[s].get_buffer()) result[s[3:]] = "\n".join(kwargs[s].get_buffer())
for k, v in result.iteritems(): for k, v in result.iteritems():
if not v: if v and isinstance(v, basestring):
continue result[k].strip()
result[k].strip()
return result return result

View File

@ -30,9 +30,8 @@ def test_run(platformio_setup, pioproject_dir):
["platformio", "run"], ["platformio", "run"],
cwd=pioproject_dir cwd=pioproject_dir
) )
output = "%s\n%s" % (result['out'], result['err']) if result['returncode'] != 0:
if "error" in output.lower(): pytest.fail(result)
pytest.fail(output)
# check .elf file # check .elf file
pioenvs_dir = join(pioproject_dir, ".pioenvs") pioenvs_dir = join(pioproject_dir, ".pioenvs")