[llvm] [LIT] replace `lit.util.mkdir` with `pathlib.Path.mkdir` (PR #163948)
    Tomohiro Kashiwada via llvm-commits 
    llvm-commits at lists.llvm.org
       
    Wed Oct 22 03:51:01 PDT 2025
    
    
  
https://github.com/kikairoya updated https://github.com/llvm/llvm-project/pull/163948
>From 2efd1285dd2206a78e425bdc58310b15b75fe3a4 Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Fri, 17 Oct 2025 20:41:22 +0900
Subject: [PATCH 1/5] [LIT][Cygwin] Skip pre-check for existence in mkdir-p
On Cygwin, a file named `file_name.exe` can be accessed without the suffix,
simply as `file_name`, as shown below:
```
$ echo > file_name.exe
$ file file_name.exe
file_name.exe: very short file (no magic)
$ file file_name
file_name: very short file (no magic)
```
In this situation, while running `mkdir file_name` works as intended,
checking for the existence of the target before calling `mkdir`
incorrectly reports that it already exists and thus skips the directory creation.
```
$ test -e file && echo exists
exists
$ mkdir file_name && echo ok
ok
$ file file_name
file: directory
```
Therefore, the existence pre-check should be skipped on Cygwin.
If the target actually already exists, such an error will be ignored anyway.
---
 llvm/utils/lit/lit/util.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/utils/lit/lit/util.py b/llvm/utils/lit/lit/util.py
index ce4c3c2df3436..a5181ab20a7e1 100644
--- a/llvm/utils/lit/lit/util.py
+++ b/llvm/utils/lit/lit/util.py
@@ -164,7 +164,7 @@ def mkdir(path):
 def mkdir_p(path):
     """mkdir_p(path) - Make the "path" directory, if it does not exist; this
     will also make directories for any missing parent directories."""
-    if not path or os.path.exists(path):
+    if not path or (sys.platform != "cygwin" and os.path.exists(path)):
         return
 
     parent = os.path.dirname(path)
>From 665e97f6f892081fc22f6d29b15e02ee2d31c78e Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Sat, 18 Oct 2025 00:21:24 +0900
Subject: [PATCH 2/5] use makedirs with exist_ok=True
---
 llvm/utils/lit/lit/util.py | 9 +--------
 1 file changed, 1 insertion(+), 8 deletions(-)
diff --git a/llvm/utils/lit/lit/util.py b/llvm/utils/lit/lit/util.py
index a5181ab20a7e1..6f5b1606a16cc 100644
--- a/llvm/utils/lit/lit/util.py
+++ b/llvm/utils/lit/lit/util.py
@@ -164,14 +164,7 @@ def mkdir(path):
 def mkdir_p(path):
     """mkdir_p(path) - Make the "path" directory, if it does not exist; this
     will also make directories for any missing parent directories."""
-    if not path or (sys.platform != "cygwin" and os.path.exists(path)):
-        return
-
-    parent = os.path.dirname(path)
-    if parent != path:
-        mkdir_p(parent)
-
-    mkdir(path)
+    os.makedirs(path, exist_ok=True)
 
 
 def listdir_files(dirname, suffixes=None, exclude_filenames=None, prefixes=None):
>From c9fc27d057d2813b7ef9ce193d5ca748d78cad43 Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Sat, 18 Oct 2025 16:53:38 +0900
Subject: [PATCH 3/5] use pathlib.Path.mkdir directly
---
 llvm/utils/lit/lit/TestRunner.py              | 15 ++++-----
 llvm/utils/lit/lit/util.py                    | 33 +++----------------
 .../tests/Inputs/shtest-glob/glob-mkdir.txt   |  8 +++++
 llvm/utils/lit/tests/shtest-glob.py           |  9 ++---
 4 files changed, 25 insertions(+), 40 deletions(-)
diff --git a/llvm/utils/lit/lit/TestRunner.py b/llvm/utils/lit/lit/TestRunner.py
index a7e2705f609af..f1346c257ec75 100644
--- a/llvm/utils/lit/lit/TestRunner.py
+++ b/llvm/utils/lit/lit/TestRunner.py
@@ -462,16 +462,15 @@ def executeBuiltinMkdir(cmd, cmd_shenv):
     stderr = StringIO()
     exitCode = 0
     for dir in args:
-        cwd = cmd_shenv.cwd
-        dir = to_unicode(dir) if kIsWindows else to_bytes(dir)
-        cwd = to_unicode(cwd) if kIsWindows else to_bytes(cwd)
-        if not os.path.isabs(dir):
-            dir = lit.util.abs_path_preserve_drive(os.path.join(cwd, dir))
+        dir = pathlib.Path(dir)
+        cwd = pathlib.Path(to_unicode(cmd_shenv.cwd))
+        if not dir.is_absolute():
+            dir = lit.util.abs_path_preserve_drive(cwd / dir)
         if parent:
-            lit.util.mkdir_p(dir)
+            dir.mkdir(parents=True, exist_ok=True)
         else:
             try:
-                lit.util.mkdir(dir)
+                dir.mkdir(exist_ok=True)
             except OSError as err:
                 stderr.write("Error: 'mkdir' command failed, %s\n" % str(err))
                 exitCode = 1
@@ -2395,7 +2394,7 @@ def runOnce(
         return out, err, exitCode, timeoutInfo, status
 
     # Create the output directory if it does not already exist.
-    lit.util.mkdir_p(os.path.dirname(tmpBase))
+    pathlib.Path(tmpBase).parent.mkdir(parents=True, exist_ok=True)
 
     # Re-run failed tests up to test.allowed_retries times.
     execdir = os.path.dirname(test.getExecPath())
diff --git a/llvm/utils/lit/lit/util.py b/llvm/utils/lit/lit/util.py
index 6f5b1606a16cc..e4e031b3e0898 100644
--- a/llvm/utils/lit/lit/util.py
+++ b/llvm/utils/lit/lit/util.py
@@ -5,6 +5,7 @@
 import math
 import numbers
 import os
+import pathlib
 import platform
 import re
 import signal
@@ -131,41 +132,17 @@ def abs_path_preserve_drive(path):
         # Since Python 3.8, os.path.realpath resolves sustitute drives,
         # so we should not use it. In Python 3.7, os.path.realpath
         # was implemented as os.path.abspath.
+        if isinstance(path, pathlib.Path):
+            return path.absolute()
         return os.path.abspath(path)
     else:
         # On UNIX, the current directory always has symbolic links resolved,
         # so any program accepting relative paths cannot preserve symbolic
         # links in paths and we should always use os.path.realpath.
+        if isinstance(path, pathlib.Path):
+            return path.resolve()
         return os.path.realpath(path)
 
-def mkdir(path):
-    try:
-        if platform.system() == "Windows":
-            from ctypes import windll
-            from ctypes import GetLastError, WinError
-
-            path = os.path.abspath(path)
-            # Make sure that the path uses backslashes here, in case
-            # python would have happened to use forward slashes, as the
-            # NT path format only supports backslashes.
-            path = path.replace("/", "\\")
-            NTPath = to_unicode(r"\\?\%s" % path)
-            if not windll.kernel32.CreateDirectoryW(NTPath, None):
-                raise WinError(GetLastError())
-        else:
-            os.mkdir(path)
-    except OSError:
-        e = sys.exc_info()[1]
-        # ignore EEXIST, which may occur during a race condition
-        if e.errno != errno.EEXIST:
-            raise
-
-
-def mkdir_p(path):
-    """mkdir_p(path) - Make the "path" directory, if it does not exist; this
-    will also make directories for any missing parent directories."""
-    os.makedirs(path, exist_ok=True)
-
 
 def listdir_files(dirname, suffixes=None, exclude_filenames=None, prefixes=None):
     """Yields files in a directory.
diff --git a/llvm/utils/lit/tests/Inputs/shtest-glob/glob-mkdir.txt b/llvm/utils/lit/tests/Inputs/shtest-glob/glob-mkdir.txt
index d1329f5dbfaae..2d4f8751fc8e7 100644
--- a/llvm/utils/lit/tests/Inputs/shtest-glob/glob-mkdir.txt
+++ b/llvm/utils/lit/tests/Inputs/shtest-glob/glob-mkdir.txt
@@ -1,2 +1,10 @@
 ## Tests glob pattern handling in the mkdir command.
+
+## This mkdir should fail because the `example_file*.input`s are regular files.
 # RUN: not mkdir %S/example_file*.input
+
+# RUN: mkdir %S/example_dir1.new
+# RUN: mkdir %S/example_dir2.new
+
+## This mkdir should succeed (so RUN should fail) because the `example_dir*.new`s are directories already exist.
+# RUN: not mkdir %S/example_dir*.new
diff --git a/llvm/utils/lit/tests/shtest-glob.py b/llvm/utils/lit/tests/shtest-glob.py
index ae90f31907d49..9ddf734e3d3a0 100644
--- a/llvm/utils/lit/tests/shtest-glob.py
+++ b/llvm/utils/lit/tests/shtest-glob.py
@@ -1,12 +1,13 @@
 ## Tests glob pattern handling in echo command.
 
 # RUN: not %{lit} -a -v %{inputs}/shtest-glob \
-# RUN: | FileCheck -dump-input=fail -match-full-lines %s
-#
+# RUN: | FileCheck -dump-input=fail -match-full-lines --implicit-check-not=Error: %s
 # END.
 
 # CHECK: UNRESOLVED: shtest-glob :: glob-echo.txt ({{[^)]*}})
 # CHECK: TypeError: string argument expected, got 'GlobItem'
 
-# CHECK: FAIL: shtest-glob :: glob-mkdir.txt ({{[^)]*}})
-# CHECK: # error: command failed with exit status: 1
+# CHECK:      FAIL: shtest-glob :: glob-mkdir.txt ({{[^)]*}})
+# CHECK:      # | Error: 'mkdir' command failed, {{.*}}Inputs/shtest-glob/example_file1.input'
+# CHECK-NEXT: # | Error: 'mkdir' command failed, {{.*}}Inputs/shtest-glob/example_file2.input'
+# CHECK:      # error: command failed with exit status: 1
>From 10db6920d8bbc73d916add4b3556e9f5f070c8bf Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Sat, 18 Oct 2025 19:35:16 +0900
Subject: [PATCH 4/5] fix test
---
 llvm/utils/lit/tests/shtest-glob.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/utils/lit/tests/shtest-glob.py b/llvm/utils/lit/tests/shtest-glob.py
index 9ddf734e3d3a0..aa4705b634a7d 100644
--- a/llvm/utils/lit/tests/shtest-glob.py
+++ b/llvm/utils/lit/tests/shtest-glob.py
@@ -8,6 +8,6 @@
 # CHECK: TypeError: string argument expected, got 'GlobItem'
 
 # CHECK:      FAIL: shtest-glob :: glob-mkdir.txt ({{[^)]*}})
-# CHECK:      # | Error: 'mkdir' command failed, {{.*}}Inputs/shtest-glob/example_file1.input'
-# CHECK-NEXT: # | Error: 'mkdir' command failed, {{.*}}Inputs/shtest-glob/example_file2.input'
+# CHECK:      # | Error: 'mkdir' command failed, {{.*}}example_file1.input'
+# CHECK-NEXT: # | Error: 'mkdir' command failed, {{.*}}example_file2.input'
 # CHECK:      # error: command failed with exit status: 1
>From a37027e2704d1786903b9bce97d201e1b8c36361 Mon Sep 17 00:00:00 2001
From: Tomohiro Kashiwada <kikairoya at gmail.com>
Date: Wed, 22 Oct 2025 19:50:51 +0900
Subject: [PATCH 5/5] Update glob-mkdir.txt
---
 llvm/utils/lit/tests/Inputs/shtest-glob/glob-mkdir.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/utils/lit/tests/Inputs/shtest-glob/glob-mkdir.txt b/llvm/utils/lit/tests/Inputs/shtest-glob/glob-mkdir.txt
index 2d4f8751fc8e7..56b3cc345edd6 100644
--- a/llvm/utils/lit/tests/Inputs/shtest-glob/glob-mkdir.txt
+++ b/llvm/utils/lit/tests/Inputs/shtest-glob/glob-mkdir.txt
@@ -6,5 +6,5 @@
 # RUN: mkdir %S/example_dir1.new
 # RUN: mkdir %S/example_dir2.new
 
-## This mkdir should succeed (so RUN should fail) because the `example_dir*.new`s are directories already exist.
+## This mkdir should succeed (so RUN should fail) because the `example_dir*.news` that already exist are directories.
 # RUN: not mkdir %S/example_dir*.new
    
    
More information about the llvm-commits
mailing list