Skip to content
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

Add fs.path.ComponentIterator and use it in Dir.makePath #16570

Merged
merged 1 commit into from
Jul 27, 2023

Conversation

squeek502
Copy link
Collaborator

Before this commit, there were three issues with the makePath implementation:

  1. The component iteration did not 'collapse' consecutive path separators; instead, it would treat a/b//c as a/b//c, a/b/, a/b, and a.
  2. Trailing path separators led to redundant makeDir calls, e.g. with the path a/b/ (if a doesn't exist), it would try to create a/b/, then try a/b, then try a, then try a/b, and finally try a/b/ again.
  3. The iteration did not treat the root of a path specially, so on Windows it could attempt to make a directory with a path like X: for something like X:\a\b\c if the X:\ drive doesn't exist. This didn't lead to any problems that I could find, but there's no reason to try to make a drive letter as a directory (or any other root path).

This commit fixes all three issues by introducing a ComponentIterator that is root-aware and handles both sequential path separators and trailing path separators and uses it in Dir.makePath. This reduces the number of makeDir calls for paths where (1) the root of the path doesn't exist, (2) there are consecutive path separators, or (3) there are trailing path separators

As an example, here are the makeDir calls that would have been made before this commit when calling makePath for a relative path like a/b//c// (where the full path needs to be created):

a/b//c//
a/b//c/
a/b//c
a/b/
a/b
a
a/b
a/b/
a/b//c
a/b//c/
a/b//c//

And after this commit:

a/b//c
a/b
a
a/b
a/b//c


Tangentially related to #14833, but only in the sense that ComponentIterator could be used there as well.

Copy link
Contributor

@matu3ba matu3ba left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking neat aside of comment nits.

Do you think test cases for utf8 and relative paths would be a good thing?

lib/std/fs/path.zig Outdated Show resolved Hide resolved
lib/std/fs/path.zig Outdated Show resolved Hide resolved
lib/std/fs/path.zig Outdated Show resolved Hide resolved
lib/std/fs/path.zig Outdated Show resolved Hide resolved
break :posix root_end_index;
},
.windows => windows: {
// Namespaces other than the Win32 file namespace are tricky
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a shorter counter-example would be more readable, but I dont have too much of an opinion on this.

lib/std/fs/path.zig Show resolved Hide resolved
Before this commit, there were three issues with the makePath implementation:

1. The component iteration did not 'collapse' consecutive path separators; instead, it would treat `a/b//c` as `a/b//c`, `a/b/`, `a/b`, and `a`.
2. Trailing path separators led to redundant `makeDir` calls, e.g. with the path `a/b/` (if `a` doesn't exist), it would try to create `a/b/`, then try `a/b`, then try `a`, then try `a/b`, and finally try `a/b/` again.
3. The iteration did not treat the root of a path specially, so on Windows it could attempt to make a directory with a path like `X:` for something like `X:\a\b\c` if the `X:\` drive doesn't exist. This didn't lead to any problems that I could find, but there's no reason to try to make a drive letter as a directory (or any other root path).

This commit fixes all three issues by introducing a ComponentIterator that is root-aware and handles both sequential path separators and trailing path separators and uses it in `Dir.makePath`. This reduces the number of `makeDir` calls for paths where (1) the root of the path doesn't exist, (2) there are consecutive path separators, or (3) there are trailing path separators

As an example, here are the makeDir calls that would have been made before this commit when calling `makePath` for a relative path like `a/b//c//` (where the full path needs to be created):

a/b//c//
a/b//c/
a/b//c
a/b/
a/b
a
a/b
a/b/
a/b//c
a/b//c/
a/b//c//

And after this commit:

a/b//c
a/b
a
a/b
a/b//c
@andrewrk andrewrk merged commit 49053cb into ziglang:master Jul 27, 2023
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants