[llvm] [LIT] replace `lit.util.mkdir` with `pathlib.Path.mkdir` (PR #163948)
Tomohiro Kashiwada via llvm-commits
llvm-commits at lists.llvm.org
Fri Oct 31 18:17:36 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/6] [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/6] 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/6] 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/6] 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/6] 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
>From cdf8adc7799d54651bcebf8ecbbfbffdfd4d3175 Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Sat, 1 Nov 2025 09:07:01 +0900
Subject: [PATCH 6/6] include `example_dir`s into source tree
---
.../lit/tests/Inputs/shtest-glob/example_dir1.input/empty | 0
.../lit/tests/Inputs/shtest-glob/example_dir2.input/empty | 0
llvm/utils/lit/tests/Inputs/shtest-glob/glob-mkdir.txt | 7 ++-----
3 files changed, 2 insertions(+), 5 deletions(-)
create mode 100644 llvm/utils/lit/tests/Inputs/shtest-glob/example_dir1.input/empty
create mode 100644 llvm/utils/lit/tests/Inputs/shtest-glob/example_dir2.input/empty
diff --git a/llvm/utils/lit/tests/Inputs/shtest-glob/example_dir1.input/empty b/llvm/utils/lit/tests/Inputs/shtest-glob/example_dir1.input/empty
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/llvm/utils/lit/tests/Inputs/shtest-glob/example_dir2.input/empty b/llvm/utils/lit/tests/Inputs/shtest-glob/example_dir2.input/empty
new file mode 100644
index 0000000000000..e69de29bb2d1d
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 56b3cc345edd6..71972411bc4cf 100644
--- a/llvm/utils/lit/tests/Inputs/shtest-glob/glob-mkdir.txt
+++ b/llvm/utils/lit/tests/Inputs/shtest-glob/glob-mkdir.txt
@@ -3,8 +3,5 @@
## 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*.news` that already exist are directories.
-# RUN: not mkdir %S/example_dir*.new
+## This mkdir should succeed (so RUN should fail) because the `example_dir*.input`s that already exist are directories.
+# RUN: not mkdir %S/example_dir*.input
More information about the llvm-commits
mailing list