Use pipefail when available.
authorRafael Espindola <rafael.espindola@gmail.com>
Fri, 26 Jul 2013 22:32:58 +0000 (22:32 +0000)
committerRafael Espindola <rafael.espindola@gmail.com>
Fri, 26 Jul 2013 22:32:58 +0000 (22:32 +0000)
This change makes test with RUN lines like
RUN: opt ... | FileCheck

fail if opt fails, even if it prints what FileCheck wants. Enabling this
found some interesting cases of broken tests that were not being noticed
because opt (or some other tool) was crashing late.

Pipefail is used when the shell supports it or when using the internal
python based tester.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@187261 91177308-0d34-0410-b5e6-96231b3b80d8

docs/CommandGuide/lit.rst
docs/ReleaseNotes.rst
test/Other/pipefail.txt [new file with mode: 0644]
utils/lit/lit/ShUtil.py
utils/lit/lit/TestRunner.py
utils/lit/lit/TestingConfig.py

index 2f6d9a155613aae92d94ad1d71259785fbc95f26..a4681fb34ca2cfb2a5c97e31d2a9da291d40c118 100644 (file)
@@ -316,6 +316,10 @@ executed, two important global variables are predefined:
  *on_clone* function will generally modify), and (3) the test path to the new
  directory being scanned.
 
+ **pipefail** Normally a test using a shell pipe fails if any of the commands
+ on the pipe fail. If this is not desired, setting this variable to false
+ makes the test fail only if the last command in the pipe fails.
+
 TEST DISCOVERY
 ~~~~~~~~~~~~~~
 
index 93f12e5974df40e649b8316b463c99c4397cdd61..e776dce29a211bbf07477f5a1a6125eeae9a4050 100644 (file)
@@ -41,6 +41,10 @@ Non-comprehensive list of changes in this release
    functionality, or simply have a lot to talk about), see the `NOTE` below
    for adding a new subsection.
 
+* The regression tests now fail if any command in a pipe fails. To disable it in
+  a directory, just add ``config.pipefail = False`` to its ``lit.local.cfg``.
+  See :doc:`Lit <CommandGuide/lit>` for the details.
+
 * Support for exception handling has been removed from the old JIT. Use MCJIT
   if you need EH support.
 
diff --git a/test/Other/pipefail.txt b/test/Other/pipefail.txt
new file mode 100644 (file)
index 0000000..241080a
--- /dev/null
@@ -0,0 +1,2 @@
+REQUIRES: shell
+RUN: ((false | true) && echo true || echo false) | grep false
index 50f79103199bd9b71c4e9c7f16ba591d4f204661..00bb40255c98bc13d5210ef593f40c7f07bddab7 100644 (file)
@@ -166,8 +166,9 @@ class ShLexer:
 ###
  
 class ShParser:
-    def __init__(self, data, win32Escapes = False):
+    def __init__(self, data, win32Escapes = False, pipefail = False):
         self.data = data
+        self.pipefail = pipefail
         self.tokens = ShLexer(data, win32Escapes = win32Escapes).lex()
     
     def lex(self):
@@ -224,7 +225,7 @@ class ShParser:
         while self.look() == ('|',):
             self.lex()
             commands.append(self.parse_command())
-        return Pipeline(commands, negate)
+        return Pipeline(commands, negate, self.pipefail)
             
     def parse(self):
         lhs = self.parse_pipeline()
index 84176996a8c8dcb496f638fde212e35ca53aeb3a..daa9b7dfbb0ee0c282671bd911e8041a84587b33 100644 (file)
@@ -245,7 +245,8 @@ def executeScriptInternal(test, litConfig, tmpBase, commands, cwd):
     cmds = []
     for ln in commands:
         try:
-            cmds.append(ShUtil.ShParser(ln, litConfig.isWindows).parse())
+            cmds.append(ShUtil.ShParser(ln, litConfig.isWindows,
+                                        test.config.pipefail).parse())
         except:
             return (Test.FAIL, "shell parser error on: %r" % ln)
 
@@ -284,6 +285,8 @@ def executeScript(test, litConfig, tmpBase, commands, cwd):
     if isWin32CMDEXE:
         f.write('\nif %ERRORLEVEL% NEQ 0 EXIT\n'.join(commands))
     else:
+        if test.config.pipefail:
+            f.write('set -o pipefail;')
         f.write('{ ' + '; } &&\n{ '.join(commands) + '; }')
     f.write('\n')
     f.close()
index a1f79a3bfc4e27f6bce3fd0f1bcc5db4db1ec210..5d5832e9bb60e0a40391212031c563125cc21780 100644 (file)
@@ -92,6 +92,7 @@ class TestingConfig:
         self.test_source_root = test_source_root
         self.excludes = set(excludes)
         self.available_features = set(available_features)
+        self.pipefail = True
 
     def clone(self, path):
         # FIXME: Chain implementations?