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

os: hard to use DirFS for cross-platform root filesystem #44279

Open
josharian opened this issue Feb 16, 2021 · 3 comments
Open

os: hard to use DirFS for cross-platform root filesystem #44279

josharian opened this issue Feb 16, 2021 · 3 comments
Milestone

Comments

@josharian
Copy link
Contributor

@josharian josharian commented Feb 16, 2021

I wrote a little package called cdup that walks a directory and each of its ancestors looking for a file/dir. This is useful e.g. to find the root of a git dir (look for .git) or a Go module (look for go.mod).

I aimed to write it using fs.FS and use os.DirFS as a bridge to the OS filesystem as needed, perhaps inside a wrapper function.

I may just be holding it wrong, but I encountered a few surprising bumps.

A typical invocation is cdup.Find(pwd, ".git"). The obvious but wrong translation of this is cdup.FindIn(os.DirFS("/"), pwd, ".git").

What is the correct root path to pass to os.DirFS on Windows? filepath.VolumeName seems like the right API to use. (I think?)

Then we must convert pwd to a relative path using filepath.Rel. On Windows, we also need to call filepath.ToSlash.

So I believe that the correct code is something like:

root := "/"
if vol := filepath.VolumeName(dir); vol != "" {
  root = vol
}
rel := filepath.Rel(root, dir)
rel = filepath.ToSlash(rel)
cdup.FindIn(os.DirFS(root), rel, ".git")

This is a surprising amount of non-obvious work for what seems like it should be a trivial bridge between fs.FS and the OS filesystem.

I'm not sure exactly what the fix should be here. Docs/examples? New package filepath API to get the OS fs root for a path? New package os API to construct a root filesystem (and expose the root for use with filepath.Rel)?

@dmitshur
Copy link
Member

@dmitshur dmitshur commented Feb 16, 2021

CC @rsc.

@bcmills
Copy link
Member

@bcmills bcmills commented Feb 16, 2021

What is the correct root path to pass to os.DirFS on Windows? filepath.VolumeName seems like the right API to use. (I think?)

IIUC there is no single root path on Windows: each drive letter is its own root.

Perhaps you could implement an fs.FS that identifies all mapped (or all local) drive letters and lists those as virtual subdirectories of the root?

@josharian
Copy link
Contributor Author

@josharian josharian commented Feb 16, 2021

At least for my purposes, I don't need a single root. I only need the root corresponding to a particular path, since I'm only walking up the tree. The broader question is interesting too, though.

(Ideally, for my purposes, I'd like to stop at filesystem boundaries, instead of traversing through mount points. But that's out of scope—the point of this issue is that it's hard to do something that feels like it should be easy. It is reasonable for detecting and stopping at mount points to be hard. 😁)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
3 participants