-
Notifications
You must be signed in to change notification settings - Fork 15.5k
[LIT] replace lit.util.mkdir with pathlib.Path.mkdir
#163948
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
@llvm/pr-subscribers-testing-tools Author: Tomohiro Kashiwada (kikairoya) ChangesOn Cygwin, a file named In this situation, while running Therefore, the existence pre-check should be skipped on Cygwin. If the target actually already exists, such an error will be ignored anyway. Full diff: https://github.com/llvm/llvm-project/pull/163948.diff 1 Files Affected:
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)
|
|
So does that mean any use of os.path.exists() is broken on cygwin? Maybe we could change it to is_dir? |
arichardson
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or maybe now that we depend on newer python we can just use the exist_ok=True parameter for mkdir?
I think, in general, most of such checks should be avoided (cf. TOCTOU).
Sure. I'll make a change to use it. |
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.
b36911f to
665e97f
Compare
|
|
llvm/utils/lit/lit/util.py
Outdated
| mkdir_p(parent) | ||
|
|
||
| mkdir(path) | ||
| os.makedirs(path, exist_ok=True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks much simpler, nice. Not a Windows expert but do we need to remap long paths using something like this?
| os.makedirs(path, exist_ok=True) | |
| if platform.system() == "Windows": | |
| if not path.startswith(r"\\?\"): | |
| path = r"\\?\" + path | |
| os.makedirs(path, exist_ok=True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure - do our python script do such path mangling anywhere else?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They do in the def mkdir(path): above.
It sounds like python3.6 supports long paths if they are enabled in the registry so there should be no need to work around it here anymore:
https://bugs.python.org/issue27731 -> https://hg.python.org/cpython/rev/26601191b368
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I see.
|
From what I've read pathlib.Path handles long windows paths correctly, so maybe the best solution would be to migrate callers of these helpers towards pathlib? |
|
OK, I'll try to replace both of |
| os.mkdir(path) | ||
| except OSError: | ||
| e = sys.exc_info()[1] | ||
| # ignore EEXIST, which may occur during a race condition |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Previously, all EEXIST errors were ignored.
We should indeed ignore races between concurrent mkdir targets, but I don't see any reason to allow races between touch target and mkdir target.
Since pathlib's exist_ok=True behaves this way, the test shtest-glob.py has been updated to reflect the new behavior.
lit.util.mkdir with pathlib.Path.mkdir
RoboTux
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM otherwise
| # 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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: remove `are'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the review.
I meant to write, "the example_dir*.news are directories" rather than "the example_dir*.news already exist".
Would "the example_dir*.news that already exist are directories." be correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes that would be fine, thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
|
I've verified that latest version resolves my initial problem about |
RoboTux
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM thanks for the work
|
@arichardson Could you take another look? |
arichardson
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One comment on the test otherwise LGTM.
| # 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| # 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 | |
| # RUN: rm -rf %t && mkdir %t | |
| # RUN: cp %S/example_file*.input %t | |
| # RUN: not mkdir %t/example_file*.input | |
| # RUN: mkdir %t/example_dir1.new | |
| # RUN: mkdir %t/example_dir2.new | |
| ## This mkdir should succeed (so RUN should fail) because the `example_dir*.news` that already exist are directories. | |
| # RUN: not mkdir %t/example_dir*.new |
I think we need to do something like the following since we shouldn't be writing to the source directory when running tests. Might be good to have a builder that bind mounts the source dir as read-only.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the suggestion.
In these particular cases, Inputs are copied to the build directory and run within there, so they won't try to write to the source tree.
llvm-project/llvm/utils/lit/CMakeLists.txt
Lines 15 to 20 in 523706f
| add_custom_target(prepare-check-lit | |
| COMMAND ${CMAKE_COMMAND} -E remove_directory "${CMAKE_CURRENT_BINARY_DIR}/tests" | |
| COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/tests" "${CMAKE_CURRENT_BINARY_DIR}/tests" | |
| COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg" "${CMAKE_CURRENT_BINARY_DIR}/tests" | |
| COMMENT "Preparing lit tests" | |
| ) |
That said, I agree that it's not good that they look like writing to the source directory.
I'd like to avoid use of another command in this test, so I've updated to include example_dirs in the source tree.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah I was not aware that %S is actually in the build tree. LGTM
|
So if everyone are ok with this, I guess we can merge it? |
|
Yes, please -- thank you as always! |
|
|
The helper function `lit.util.mkdir_p` has been removed in llvm/llvm-project#163948 . Instead of that, call `pathlib` functions directly.
The helper function `lit.util.mkdir_p` has been removed in llvm/llvm-project#163948 . Instead of that, call `pathlib` functions directly.
lit.util.mkdirandlit.util.mkdir_pwere written during the Python 2.x era.Since modern
pathlibfunctions have similar functionality, we can simply use those instead.If you encounter a path length issue after this change, the registry value
LongPathsEnabledmust be set as described in https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation . Note that the Python runtime is already marked as alongPathAwareexecutable.Background:
On Cygwin, a file named
file_name.execan be accessed without the suffix, simply asfile_name, as shown below:In this situation, while running
mkdir file_nameworks as intended, checking for the existence of the target before callingmkdirincorrectly reports that it already exists and thus skips the directory creation.Therefore, the existence pre-check should be skipped on Cygwin. Instead of add a workaround, refactored them.