[Lit] Add pushd and popd builtins
authorDavid Goldman <davg@google.com>
Thu, 12 May 2022 20:32:29 +0000 (16:32 -0400)
committerDavid Goldman <davg@google.com>
Thu, 12 May 2022 23:24:30 +0000 (19:24 -0400)
This behaves just like the sh/cmd.exe equivalents.

pushd/popd are useful to verify path handling of the driver,
typically testing prefix maps or relative path handling.

Differential Revision: https://reviews.llvm.org/D125502

llvm/utils/lit/lit/TestRunner.py
llvm/utils/lit/tests/Inputs/shtest-pushd-popd/lit.cfg [new file with mode: 0644]
llvm/utils/lit/tests/Inputs/shtest-pushd-popd/popd-args.txt [new file with mode: 0644]
llvm/utils/lit/tests/Inputs/shtest-pushd-popd/popd-no-stack.txt [new file with mode: 0644]
llvm/utils/lit/tests/Inputs/shtest-pushd-popd/pushd-popd-ok.txt [new file with mode: 0644]
llvm/utils/lit/tests/Inputs/shtest-pushd-popd/pushd-too-many-args.txt [new file with mode: 0644]
llvm/utils/lit/tests/shtest-pushd-popd.py [new file with mode: 0644]

index de711b4..0242e0b 100644 (file)
@@ -57,12 +57,20 @@ class ShellEnvironment(object):
 
     """Mutable shell environment containing things like CWD and env vars.
 
-    Environment variables are not implemented, but cwd tracking is.
+    Environment variables are not implemented, but cwd tracking is. In addition,
+    we maintain a dir stack for pushd/popd.
     """
 
     def __init__(self, cwd, env):
         self.cwd = cwd
         self.env = dict(env)
+        self.dirStack = []
+
+    def change_dir(self, newdir):
+        if os.path.isabs(newdir):
+            self.cwd = newdir
+        else:
+            self.cwd = os.path.realpath(os.path.join(self.cwd, newdir))
 
 class TimeoutHelper(object):
     """
@@ -275,17 +283,30 @@ def updateEnv(env, args):
 def executeBuiltinCd(cmd, shenv):
     """executeBuiltinCd - Change the current directory."""
     if len(cmd.args) != 2:
-        raise InternalShellError("'cd' supports only one argument")
-    newdir = cmd.args[1]
+        raise InternalShellError(cmd, "'cd' supports only one argument")
     # Update the cwd in the parent environment.
-    if os.path.isabs(newdir):
-        shenv.cwd = newdir
-    else:
-        shenv.cwd = os.path.realpath(os.path.join(shenv.cwd, newdir))
+    shenv.change_dir(cmd.args[1])
     # The cd builtin always succeeds. If the directory does not exist, the
     # following Popen calls will fail instead.
     return ShellCommandResult(cmd, "", "", 0, False)
 
+def executeBuiltinPushd(cmd, shenv):
+    """executeBuiltinPushd - Change the current dir and save the old."""
+    if len(cmd.args) != 2:
+        raise InternalShellError(cmd, "'pushd' supports only one argument")
+    shenv.dirStack.append(shenv.cwd)
+    shenv.change_dir(cmd.args[1])
+    return ShellCommandResult(cmd, "", "", 0, False)
+
+def executeBuiltinPopd(cmd, shenv):
+    """executeBuiltinPopd - Restore a previously saved working directory."""
+    if len(cmd.args) != 1:
+        raise InternalShellError(cmd, "'popd' does not support arguments")
+    if not shenv.dirStack:
+        raise InternalShellError(cmd, "popd: directory stack empty")
+    shenv.cwd = shenv.dirStack.pop()
+    return ShellCommandResult(cmd, "", "", 0, False)
+
 def executeBuiltinExport(cmd, shenv):
     """executeBuiltinExport - Set an environment variable."""
     if len(cmd.args) != 2:
@@ -629,6 +650,8 @@ def _executeShCmd(cmd, shenv, results, timeoutHelper):
                        'export': executeBuiltinExport,
                        'echo': executeBuiltinEcho,
                        'mkdir': executeBuiltinMkdir,
+                       'popd': executeBuiltinPopd,
+                       'pushd': executeBuiltinPushd,
                        'rm': executeBuiltinRm,
                        ':': executeBuiltinColon}
     # To avoid deadlock, we use a single stderr stream for piped
diff --git a/llvm/utils/lit/tests/Inputs/shtest-pushd-popd/lit.cfg b/llvm/utils/lit/tests/Inputs/shtest-pushd-popd/lit.cfg
new file mode 100644 (file)
index 0000000..e7c2092
--- /dev/null
@@ -0,0 +1,4 @@
+import lit.formats
+config.name = 'shtest-pushd-popd'
+config.suffixes = ['.txt']
+config.test_format = lit.formats.ShTest(execute_external=False)
diff --git a/llvm/utils/lit/tests/Inputs/shtest-pushd-popd/popd-args.txt b/llvm/utils/lit/tests/Inputs/shtest-pushd-popd/popd-args.txt
new file mode 100644 (file)
index 0000000..9ebbf1b
--- /dev/null
@@ -0,0 +1 @@
+# RUN: popd invalid
\ No newline at end of file
diff --git a/llvm/utils/lit/tests/Inputs/shtest-pushd-popd/popd-no-stack.txt b/llvm/utils/lit/tests/Inputs/shtest-pushd-popd/popd-no-stack.txt
new file mode 100644 (file)
index 0000000..2b01687
--- /dev/null
@@ -0,0 +1 @@
+# RUN: popd
\ No newline at end of file
diff --git a/llvm/utils/lit/tests/Inputs/shtest-pushd-popd/pushd-popd-ok.txt b/llvm/utils/lit/tests/Inputs/shtest-pushd-popd/pushd-popd-ok.txt
new file mode 100644 (file)
index 0000000..61a9583
--- /dev/null
@@ -0,0 +1,8 @@
+# RUN: rm -rf %t/UserFoo && mkdir -p %t/UserFoo/FooDocs
+# RUN: touch %t/UserFoo/user.txt %t/UserFoo/FooDocs/doc.txt
+# RUN: pushd %t/UserFoo
+# RUN: pushd FooDocs
+# RUN: cat doc.txt
+# RUN: popd
+# RUN: cat user.txt
+# RUN: popd
\ No newline at end of file
diff --git a/llvm/utils/lit/tests/Inputs/shtest-pushd-popd/pushd-too-many-args.txt b/llvm/utils/lit/tests/Inputs/shtest-pushd-popd/pushd-too-many-args.txt
new file mode 100644 (file)
index 0000000..01d2420
--- /dev/null
@@ -0,0 +1 @@
+# RUN: pushd a b
\ No newline at end of file
diff --git a/llvm/utils/lit/tests/shtest-pushd-popd.py b/llvm/utils/lit/tests/shtest-pushd-popd.py
new file mode 100644 (file)
index 0000000..26296a7
--- /dev/null
@@ -0,0 +1,24 @@
+# Check the pushd and popd commands
+
+# RUN: not %{lit} -a -v %{inputs}/shtest-pushd-popd \
+# RUN: | FileCheck -match-full-lines %s
+#
+# END.
+
+# CHECK: -- Testing: 4 tests{{.*}}
+
+# CHECK: FAIL: shtest-pushd-popd :: popd-args.txt ({{[^)]*}})
+# CHECK: $ "popd" "invalid"
+# CHECK: 'popd' does not support arguments
+
+# CHECK: FAIL: shtest-pushd-popd :: popd-no-stack.txt ({{[^)]*}})
+# CHECK: $ "popd"
+# CHECK: popd: directory stack empty
+
+# CHECK: FAIL: shtest-pushd-popd :: pushd-too-many-args.txt ({{[^)]*}})
+# CHECK: $ "pushd" "a" "b"
+# CHECK: 'pushd' supports only one argument
+
+# CHECK: Passed:  1
+# CHECK: Failed:  3
+# CHECK-NOT: {{.}}