Skip to content

Commit 2d53d21

Browse files
committed
Fix bug with invalid process's "return code" when PlatformIO has internal error
1 parent 1fc6b22 commit 2d53d21

File tree

7 files changed

+48
-22
lines changed

7 files changed

+48
-22
lines changed

HISTORY.rst

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

3537

3638
0.10.2 (2015-01-06)

platformio/__main__.py

+9-9
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@
88

99
import click
1010

11-
from platformio import __version__, maintenance
12-
from platformio.exception import PlatformioException, UnknownCLICommand
11+
from platformio import __version__, exception, maintenance
1312
from platformio.util import get_source_dir
1413

1514

@@ -31,7 +30,7 @@ def get_command(self, ctx, name):
3130
mod = __import__("platformio.commands." + name,
3231
None, None, ["cli"])
3332
except ImportError:
34-
raise UnknownCLICommand(name)
33+
raise exception.UnknownCLICommand(name)
3534
return mod.cli
3635

3736

@@ -52,12 +51,13 @@ def main():
5251
try:
5352
cli(None)
5453
except Exception as e: # pylint: disable=W0703
55-
maintenance.on_platformio_exception(e)
56-
if isinstance(e, PlatformioException):
57-
click.echo("Error: " + str(e), err=True)
58-
sys_exit(1)
59-
else:
60-
print format_exc()
54+
if not isinstance(e, exception.ReturnErrorCode):
55+
maintenance.on_platformio_exception(e)
56+
if isinstance(e, exception.PlatformioException):
57+
click.echo("Error: " + str(e), err=True)
58+
else:
59+
click.echo(format_exc(), err=True)
60+
sys_exit(1)
6161

6262

6363
if __name__ == "__main__":

platformio/commands/run.py

+9-2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ def cli(ctx, environment, target, upload_port):
3636
getmtime(_pioenvs_dir)):
3737
rmtree(_pioenvs_dir)
3838

39+
found_error = False
3940
_first_done = False
4041
for section in config.sections():
4142
# skip main configuration section
@@ -56,9 +57,13 @@ def cli(ctx, environment, target, upload_port):
5657
if _first_done:
5758
click.echo()
5859

59-
process_environment(ctx, envname, options, target, upload_port)
60+
if not process_environment(ctx, envname, options, target, upload_port):
61+
found_error = True
6062
_first_done = True
6163

64+
if found_error:
65+
raise exception.ReturnErrorCode()
66+
6267

6368
def process_environment(ctx, name, options, targets, upload_port):
6469
terminal_width, _ = click.get_terminal_size()
@@ -72,8 +77,8 @@ def process_environment(ctx, name, options, targets, upload_port):
7277
click.secho("-" * terminal_width, bold=True)
7378

7479
result = _run_environment(ctx, name, options, targets, upload_port)
75-
is_error = "error" in result['err'].lower()
7680

81+
is_error = result['returncode'] != 0
7782
summary_text = " Took %.2f seconds " % (time() - start_time)
7883
half_line = "=" * ((terminal_width - len(summary_text) - 10) / 2)
7984
click.echo("%s [%s]%s%s" % (
@@ -84,6 +89,8 @@ def process_environment(ctx, name, options, targets, upload_port):
8489
half_line
8590
), err=is_error)
8691

92+
return not is_error
93+
8794

8895
def _run_environment(ctx, name, options, targets, upload_port):
8996
variables = ["PIOENV=" + name]

platformio/exception.py

+4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ def __str__(self): # pragma: no cover
1313
return Exception.__str__(self)
1414

1515

16+
class ReturnErrorCode(PlatformioException):
17+
pass
18+
19+
1620
class AbortedByUser(PlatformioException):
1721

1822
MESSAGE = "Aborted by user"

platformio/platforms/base.py

+13-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Copyright (C) Ivan Kravets <[email protected]>
22
# See LICENSE for details.
33

4+
import re
45
from imp import load_source
56
from os import listdir
67
from os.path import isdir, isfile, join
@@ -76,6 +77,10 @@ def newPlatform(cls, name):
7677
class BasePlatform(object):
7778

7879
PACKAGES = {}
80+
LINE_ERROR_RE = re.compile(r"(\s+error|error[:\s]+)", re.I)
81+
82+
def __init__(self):
83+
self._found_error = False
7984

8085
def get_name(self):
8186
return self.__class__.__name__[:-8].lower()
@@ -214,6 +219,7 @@ def run(self, variables, targets):
214219
variables.append(
215220
"PIOPACKAGE_%s=%s" % (options['alias'].upper(), name))
216221

222+
self._found_error = False
217223
try:
218224
result = util.exec_command(
219225
[
@@ -227,9 +233,10 @@ def run(self, variables, targets):
227233
except OSError:
228234
raise exception.SConsNotInstalled()
229235

230-
return self.after_run(result)
236+
assert "returncode" in result
237+
if self._found_error:
238+
result['returncode'] = 1
231239

232-
def after_run(self, result): # pylint: disable=R0201
233240
return result
234241

235242
def on_run_out(self, line): # pylint: disable=R0201
@@ -239,5 +246,7 @@ def on_run_out(self, line): # pylint: disable=R0201
239246
click.secho(line, fg=fg)
240247

241248
def on_run_err(self, line): # pylint: disable=R0201
242-
click.secho(line, err=True,
243-
fg="red" if "error" in line.lower() else "yellow")
249+
is_error = self.LINE_ERROR_RE.search(line) is not None
250+
if is_error:
251+
self._found_error = True
252+
click.secho(line, err=True, fg="red" if is_error else "yellow")

platformio/util.py

+9-4
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,12 @@ def change_filemtime(path, time):
117117

118118

119119
def exec_command(*args, **kwargs):
120-
result = {"out": None, "err": None}
120+
result = {
121+
"out": None,
122+
"err": None,
123+
"returncode": None
124+
}
125+
121126
default = dict(
122127
stdout=subprocess.PIPE,
123128
stderr=subprocess.PIPE,
@@ -129,6 +134,7 @@ def exec_command(*args, **kwargs):
129134
p = subprocess.Popen(*args, **kwargs)
130135
try:
131136
result['out'], result['err'] = p.communicate()
137+
result['returncode'] = p.returncode
132138
except KeyboardInterrupt:
133139
for s in ("stdout", "stderr"):
134140
if isinstance(kwargs[s], AsyncPipe):
@@ -141,9 +147,8 @@ def exec_command(*args, **kwargs):
141147
result[s[3:]] = "\n".join(kwargs[s].get_buffer())
142148

143149
for k, v in result.iteritems():
144-
if not v:
145-
continue
146-
result[k].strip()
150+
if v and isinstance(v, basestring):
151+
result[k].strip()
147152

148153
return result
149154

tests/test_examples.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,8 @@ def test_run(platformio_setup, pioproject_dir):
3030
["platformio", "run"],
3131
cwd=pioproject_dir
3232
)
33-
output = "%s\n%s" % (result['out'], result['err'])
34-
if "error" in output.lower():
35-
pytest.fail(output)
33+
if result['returncode'] != 0:
34+
pytest.fail(result)
3635

3736
# check .elf file
3837
pioenvs_dir = join(pioproject_dir, ".pioenvs")

0 commit comments

Comments
 (0)