Commit 2f92b674 authored by Dmitry Blinov's avatar Dmitry Blinov

set -e for shell commands

If not set, the commands in the middle of custom configure-command,
pre-build, post-build etc can fail without resulting in SystemError
for user and without stopping cmmi process, which thus can formally
succeed despite being misconfigured or in some cases with the code
not even built.
This is because when executing a multiline command, only the exit
status of the last one actually gets caught by check_call().

Setting -e makes debugging easier by allowing shell to terminate
mid-way if errors (non-zero exit status) occur.

-e only covers 'simple commands', and does not affect 'if' tests
and more complex cases where non-zero exit status is expected to
occur normally.
Detailed description of -e effects can be seen in the POSIX
standard:

https://pubs.opengroup.org/onlinepubs/009695399/utilities/set.html
parent ab0e85d1
...@@ -1058,7 +1058,7 @@ developer can try same build process as the recipe tried. ...@@ -1058,7 +1058,7 @@ developer can try same build process as the recipe tried.
Installing package. Installing package.
package: Checking whether package is installed at shared path: /shared/package/FIRST_SHARED_PACKAGE_HASH package: Checking whether package is installed at shared path: /shared/package/FIRST_SHARED_PACKAGE_HASH
package: [ENV] FOO = bar package: [ENV] FOO = bar
package: Command './configure --prefix="/shared/package/FIRST_SHARED_PACKAGE_HASH"' returned non-zero exit status 127. package: Command 'set -e;./configure --prefix="/shared/package/FIRST_SHARED_PACKAGE_HASH"' returned non-zero exit status 127.
package: Compilation error. The package is left as is at /shared/package/FIRST_SHARED_PACKAGE_HASH__compile__ where you can inspect what went wrong. package: Compilation error. The package is left as is at /shared/package/FIRST_SHARED_PACKAGE_HASH__compile__ where you can inspect what went wrong.
A shell script slapos.recipe.build.env.sh has been generated. You can source it in your shell to reproduce build environment. A shell script slapos.recipe.build.env.sh has been generated. You can source it in your shell to reproduce build environment.
/bin/sh: 1: ./configure: not found /bin/sh: 1: ./configure: not found
...@@ -1078,7 +1078,7 @@ Next time buildout runs, it detects that the build failed, remove the compile di ...@@ -1078,7 +1078,7 @@ Next time buildout runs, it detects that the build failed, remove the compile di
package: Checking whether package is installed at shared path: /shared/package/FIRST_SHARED_PACKAGE_HASH package: Checking whether package is installed at shared path: /shared/package/FIRST_SHARED_PACKAGE_HASH
package: [ENV] FOO = bar package: [ENV] FOO = bar
package: Removing already existing directory /shared/package/FIRST_SHARED_PACKAGE_HASH__compile__ package: Removing already existing directory /shared/package/FIRST_SHARED_PACKAGE_HASH__compile__
package: Command './configure --prefix="/shared/package/FIRST_SHARED_PACKAGE_HASH"' returned non-zero exit status 127. package: Command 'set -e;./configure --prefix="/shared/package/FIRST_SHARED_PACKAGE_HASH"' returned non-zero exit status 127.
package: Compilation error. The package is left as is at /shared/package/FIRST_SHARED_PACKAGE_HASH__compile__ where you can inspect what went wrong. package: Compilation error. The package is left as is at /shared/package/FIRST_SHARED_PACKAGE_HASH__compile__ where you can inspect what went wrong.
A shell script slapos.recipe.build.env.sh has been generated. You can source it in your shell to reproduce build environment. A shell script slapos.recipe.build.env.sh has been generated. You can source it in your shell to reproduce build environment.
/bin/sh: 1: ./configure: not found /bin/sh: 1: ./configure: not found
......
...@@ -258,7 +258,7 @@ class Recipe(object): ...@@ -258,7 +258,7 @@ class Recipe(object):
"""Run the given ``cmd`` in a child process.""" """Run the given ``cmd`` in a child process."""
log = logging.getLogger(self.name) log = logging.getLogger(self.name)
try: try:
subprocess.check_call(cmd, shell=True, subprocess.check_call('set -e;' + cmd, shell=True,
env=self.augmented_environment(), close_fds=True) env=self.augmented_environment(), close_fds=True)
except Exception as e: except Exception as e:
log.error(e) log.error(e)
......
...@@ -163,6 +163,14 @@ class NonInformativeTests(unittest.TestCase): ...@@ -163,6 +163,14 @@ class NonInformativeTests(unittest.TestCase):
with self.assertRaises(zc.buildout.UserError): with self.assertRaises(zc.buildout.UserError):
recipe.run('this-command-does-not-exist') recipe.run('this-command-does-not-exist')
def test_stop_shell_on_error_midway(self):
recipe = self.make_recipe({}, 'test', {
'url': 'file://%s/testdata/package-0.0.0.tar.gz' % os.path.dirname(__file__),
})
recipe.run('true \n true \n true')
with self.assertRaises(zc.buildout.UserError):
recipe.run('true \n false \n true')
def test_call_script__bbb_for_callable_with_two_parameters(self): def test_call_script__bbb_for_callable_with_two_parameters(self):
recipe = self.make_recipe({}, 'test', { recipe = self.make_recipe({}, 'test', {
'url': 'file://%s/testdata/package-0.0.0.tar.gz' % os.path.dirname(__file__), 'url': 'file://%s/testdata/package-0.0.0.tar.gz' % os.path.dirname(__file__),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment