Repository: kivy/buildozer

Issue:
Buildozer exit code on recipe fail
My `cffi` recipe build failed, but `buildozer` exit code was `0`. I'm expecting this to be the same as the recipe exit code (`ErrorReturnCode_1`) or at least different than zero.
See debug trace below:
```
[INFO]:    Installing cffi into site-packages
[INFO]:    -> directory context /home/user/.buildozer/android/platform/build/build/other_builds/cffi-python2/armeabi-v7a/cffi
[INFO]:    -> running hostpython setup.py install -O2 --root=/home/user/.buildozer/android/platform/build/bui...(and 69 more)
           working: reading manifest template 'MANIFEST.in'                    [INFO]:    Rebuilding compiled components in cffi
[INFO]:    -> running hostpython setup.py clean --all
           working: removing 'build/lib.linux-x86_64-2.7' (and everything under it)                                [INFO]:    -> running hostpython setup.py build_ext -v
Exception in thread background thread for pid 11797:
Traceback (most recent call last):
  File "/usr/lib/python2.7/threading.py", line 801, in __bootstrap_inner
    self.run()
  File "/usr/lib/python2.7/threading.py", line 754, in run
    self.__target(*self.__args, **self.__kwargs)
  File "/home/user/.local/lib/python2.7/site-packages/sh.py", line 1540, in wrap
    fn(*args, **kwargs)
  File "/home/user/.local/lib/python2.7/site-packages/sh.py", line 2459, in background_thread
    handle_exit_code(exit_code)
  File "/home/user/.local/lib/python2.7/site-packages/sh.py", line 2157, in fn
    return self.command.handle_command_exit_code(exit_code)
  File "/home/user/.local/lib/python2.7/site-packages/sh.py", line 815, in handle_command_exit_code
    raise exc
ErrorReturnCode_1:

  RAN: /home/user/.buildozer/android/platform/build/build/other_builds/hostpython2/desktop/hostpython2/hostpython setup.py build_ext -v

  STDOUT:
running build_ext
failed to import Cython: /home/user/.local/lib/python2.7/site-packages/Cython/Compiler/Scanning.so: undefined symbol: PyUnicodeUCS4_DecodeUTF8
error: Cython does not appear to be installed


  STDERR:


          [INFO]:    Building compiled components in cffinstalled
[INFO]:    -> directory context /home/user/.buildozer/android/platform/build/build/other_builds/libffi/armeabi-v7a/libffi
[INFO]:    <- directory context /home/user/.buildozer/android/platform/build/build/other_builds/cffi-python2/armeabi-v7a/cffi
[INFO]:    -> directory context /home/user/.buildozer/android/platform/build/build/other_builds/cffi-python2/armeabi-v7a/cffi
[INFO]:    -> running hostpython setup.py clean --all
Failed as expected. Rebuilding...
           working: running clea[INFO]:    -> running hostpython setup.py build_ext -v
           working: c/_cffi_backend.c:7485:5: warning: dere[INFO]:    -> running find build/lib.linux-x86_64-2.7 -name "*.o" -exec arm-linux-androideabi-strip --strip-unneeded {} ;
[INFO]:    <- directory context /home/user/.buildozer/android/platform/build/build/other_builds/cffi-python2/armeabi-v7a/cffi
[INFO]:    -> directory context /home/user/.buildozer/android/platform/build/build/other_builds/libffi/armeabi-v7a/libffi
[INFO]:    <- directory context /home/user/.buildozer/android/platform/build/build/other_builds/cffi-python2/armeabi-v7a/cffi
[INFO]:    Installing cffi into site-packages
[INFO]:    -> directory context /home/user/.buildozer/android/platform/build/build/other_builds/cffi-python2/armeabi-v7a/cffi
[INFO]:    -> running hostpython setup.py install -O2 --root=/home/user/.buildozer/android/platform/build/bui...(and 69 more)
           working: writing manifes[INFO]:    Rebuilding compiled components in cffi
[INFO]:    -> running hostpython setup.py clean --all
           working: removing 'build/lib.linux-x86_64-2.7' (and everythi[INFO]:    -> running hostpython setup.py build_ext -v
           working: error: Cython does not appear to be installed                                          Exception in thread background thread for pid 11881:
Traceback (most recent call last):
  File "/usr/lib/python2.7/threading.py", line 801, in __bootstrap_inner
    self.run()
  File "/usr/lib/python2.7/threading.py", line 754, in run
    self.__target(*self.__args, **self.__kwargs)
  File "/home/user/.local/lib/python2.7/site-packages/sh.py", line 1540, in wrap
    fn(*args, **kwargs)
  File "/home/user/.local/lib/python2.7/site-packages/sh.py", line 2459, in background_thread
    handle_exit_code(exit_code)
  File "/home/user/.local/lib/python2.7/site-packages/sh.py", line 2157, in fn
    return self.command.handle_command_exit_code(exit_code)
  File "/home/user/.local/lib/python2.7/site-packages/sh.py", line 815, in handle_command_exit_code
    raise exc
ErrorReturnCode_1:

  RAN: /home/user/.buildozer/android/platform/build/build/other_builds/hostpython2/desktop/hostpython2/hostpython setup.py build_ext -v

  STDOUT:
running build_ext
failed to import Cython: /home/user/.local/lib/python2.7/site-packages/Cython/Compiler/Scanning.so: undefined symbol: PyUnicodeUCS4_DecodeUTF8
error: Cython does not appear to be installed


  STDERR:


Traceback (most recent call last):
  File "/usr/lib/python2.7/runpy.py", line 174, in _run_module_as_main
    "__main__", fname, loader, pkg_name)
  File "/usr/lib/python2.7/runpy.py", line 72, in _run_code
    exec code in run_globals
  File "/home/user/.buildozer/android/platform/python-for-android-new-toolchain/pythonforandroid/toolchain.py", line 977, in <module>
    main()
  File "/home/user/.buildozer/android/platform/python-for-android-new-toolchain/pythonforandroid/toolchain.py", line 973, in main
    ToolchainCL()
  File "/home/user/.buildozer/android/platform/python-for-android-new-toolchain/pythonforandroid/toolchain.py", line 512, in __init__
    getattr(self, args.subparser_name.replace('-', '_'))(args)
  File "/home/user/.buildozer/android/platform/python-for-android-new-toolchain/pythonforandroid/toolchain.py", line 147, in wrapper_func
    build_dist_from_args(ctx, dist, args)
  File "/home/user/.buildozer/android/platform/python-for-android-new-toolchain/pythonforandroid/toolchain.py", line 191, in build_dist_from_args
    build_recipes(build_order, python_modules, ctx)
  File "pythonforandroid/build.py", line 573, in build_recipes
  File "/home/user/src/python-for-android/recipes/cffi/__init__.py", line 28, in build_arch
    super(CffiRecipe, self).build_arch(arch)
  File "pythonforandroid/recipe.py", line 853, in build_arch
  File "pythonforandroid/recipe.py", line 826, in install_python_package
  File "pythonforandroid/recipe.py", line 871, in install_hostpython_package
  File "pythonforandroid/recipe.py", line 880, in rebuild_compiled_components
  File "pythonforandroid/logger.py", line 176, in shprint
  File "/home/user/.local/lib/python2.7/site-packages/sh.py", line 863, in next
    self.wait()
  File "/home/user/.local/lib/python2.7/site-packages/sh.py", line 792, in wait
    self.handle_command_exit_code(exit_code)
  File "/home/user/.local/lib/python2.7/site-packages/sh.py", line 815, in handle_command_exit_code
    raise exc
sh.ErrorReturnCode_1:

  RAN: /home/user/.buildozer/android/platform/build/build/other_builds/hostpython2/desktop/hostpython2/hostpython setup.py build_ext -v

  STDOUT:
running build_ext
failed to import Cython: /home/user/.local/lib/python2.7/site-packages/Cython/Compiler/Scanning.so: undefined symbol: PyUnicodeUCS4_DecodeUTF8
error: Cython does not appear to be installed


  STDERR:

# Command failed: /usr/bin/python -m pythonforandroid.toolchain create --dist_name=pywallet --bootstrap=sdl2 --requirements=hostpython2,pyelliptic==1.5.7,cffi,secp256k1==b0452e6 --arch armeabi-v7a --copy-libs --local-recipes /home/user/src/python-for-android/recipes --color=always --storage-dir=/home/user/.buildozer/android/platform/build
# 
# Buildozer failed to execute the last command
# The error might be hidden in the log above this error
# Please read the full log, and search for it before
# raising an issue with buildozer itself.
# In case of a bug report, please add a full log with log_level = 2
user@1c8a0ea420de:~$ echo $?
0
```

Discussion:

Patch:
diff --git a/buildozer/scripts/client.py b/buildozer/scripts/client.py
index e30a9b4..fcf41ef 100644
--- a/buildozer/scripts/client.py
+++ b/buildozer/scripts/client.py
@@ -14,9 +14,10 @@ def main():
     except BuildozerCommandException:
         # don't show the exception in the command line. The log already show
         # the command failed.
-        pass
+        sys.exit(1)
     except BuildozerException as error:
         Buildozer().error('%s' % error)
+        sys.exit(1)
 
 if __name__ == '__main__':
     main()


Test patch:
diff --git a/tests/scripts/__init__.py b/tests/scripts/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/scripts/test_client.py b/tests/scripts/test_client.py
new file mode 100644
index 0000000..4ab189b
--- /dev/null
+++ b/tests/scripts/test_client.py
@@ -0,0 +1,26 @@
+import sys
+import mock
+import unittest
+from buildozer import BuildozerCommandException
+from buildozer.scripts import client
+
+
+class TestClient(unittest.TestCase):
+
+    def test_run_command_called(self):
+        """
+        Checks Buildozer.run_command() is being called with arguments from command line.
+        """
+        with mock.patch('buildozer.Buildozer.run_command') as m_run_command:
+            client.main()
+        assert m_run_command.call_args_list == [mock.call(sys.argv[1:])]
+
+    def test_exit_code(self):
+        """
+        Makes sure the CLI exits with error code on BuildozerCommandException, refs #674.
+        """
+        with mock.patch('buildozer.Buildozer.run_command') as m_run_command:
+            m_run_command.side_effect = BuildozerCommandException()
+            with self.assertRaises(SystemExit) as context:
+                client.main()
+        assert context.exception.code == 1