-
-
Notifications
You must be signed in to change notification settings - Fork 357
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
interp: Initial support for fs.FS. #799
Conversation
I haven't added any tests yet, this is just a first pass to see if this is a good idea. I converted all the obvious filesystem I could find that made sense. There are a few issues though: 1. Yet another variant of LookPath called LookPathDirFS was added. 2. fs.FS is read-only, so there will still be a split of responsibilities between the FS and OpenHandler 3. fs.FS does not allow "rooted" paths, so these paths are remapped, eg. "/" => ".", "/etc/passwd" => "etc/passwd" - returned errors that include the path will use these remapped forms.
@@ -2903,7 +2903,7 @@ var runTestsUnix = []runTest{ | |||
}, | |||
{ | |||
"cd /; sure/is/missing", | |||
"stat /sure/is/missing: no such file or directory\nexit status 127 #JUSTERR", | |||
"stat //sure/is/missing: no such file or directory\nexit status 127 #JUSTERR", |
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.
It's not yet clear to me why this is happening.
Entirely reasonable. We could clean those up with v4.
Good catch. I've subscribed to golang/go#45757, though I don't think that will arrive soon, so we shouldn't just wait around. We could consider designing our own extra methods on top of Your idea to keep using OpenHandler for write access seems fine. It still means that full coverage of the filesystem requires using two handlers rather than one, but I don't see another way until the upstream issue above is resolved.
Also sounds reasonable. |
I wonder if replacing |
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.
I think my biggest concern here is Windows; otherwise looks good!
@@ -59,6 +61,9 @@ type Runner struct { | |||
|
|||
alias map[string]alias | |||
|
|||
// Filesystem to use. Defaults to os.DirFS("/") |
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.
// Filesystem to use. Defaults to os.DirFS("/") | |
// Filesystem to use. Defaults to os.DirFS("/"). |
// FS sets the fs.FS used for filesystem file and directory read operations. | ||
func FS(fs fs.FS) RunnerOption { | ||
return func(r *Runner) error { | ||
r.fs = fs |
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.
I would mimic what StdIO does with io.Discard; otherwise you can end up with a nil r.fs
if the user provides FS(nil)
.
This also enables the user to overwrite a previous option with whatever our default is, without having to write out os.DirFS("/")
themselves.
} | ||
|
||
// LookPathDirFS is like LookPathDir but retrieves all state from the Runner. | ||
func LookPathDirFS(vfs fs.FS, cwd string, env expand.Environ, file string) (string, error) { |
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.
but retrieves all state from the Runner
Hmm, what runner?
I think you should also document that you expect vfs
to correspond to the root of the filesystem. Perhaps call it rootFS
to clarify. I'd also document the same assumption in lookPathDir.
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.
whoops, this is a leftover comment from a previous version of the function.
if path == "/" { | ||
return "." | ||
} | ||
return strings.TrimPrefix(path, "/") |
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 also sounds like it won't support Windows :)
if err != nil { | ||
return nil, err | ||
} | ||
infos := make([]os.FileInfo, len(dirents)) |
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.
I'd perhaps add here:
// TODO(v4): use io/fs directly in ReadDir
I understand that OpenHandler will still be used for reading files; that seems fine as well, and it's probably more consistent with what users will expect. |
Mmm yeah I wonder how we can deal with Windows in a consistent manner. |
Perhaps document that, on Windows, the paths will be of the form |
How do multiple drives currently work in the interpreter? Are they in the form |
It looks like, again, there isn't a great solution for Windows at the moment. |
Thanks for looking; looks like I was already subscribed, but I forgot that the issue existed. How about we simply don't support Windows on this handler for the time being, and we cite golang/go#44279 as the reason why? I only see two alternatives, neither of which are particularly better:
|
The interpreter uses paths in the native form; so it can have |
As I re-read my own comment, I realize that "simply" is incorrect. Your refactor swaps us to using
|
Yet another option is to give up, say that It doesn't feel like a good solution long-term, as I'm pretty confident that we'll get some solution to I slightly lean towards giving up for the time being. I really appreciate all the effort and patience you've invested here :) I would probably not have suggested that we try a |
Yeah, I agree with that assessment.
No problem at all, it wasn't obvious at all to me that we'd hit these issues either. It was only a couple of hours of work, and it was worth a shot :) |
DO NOT MERGE: keeping for future reference. See #799 as to why io/fs isn't ready. -- I haven't added any tests yet, this is just a first pass to see if this is a good idea. I converted all the obvious filesystem I could find that made sense. There are a few issues though: 1. Yet another variant of LookPath called LookPathDirFS was added. 2. fs.FS is read-only, so there will still be a split of responsibilities between the FS and OpenHandler 3. fs.FS does not allow "rooted" paths, so these paths are remapped, eg. "/" => ".", "/etc/passwd" => "etc/passwd" - returned errors that include the path will use these remapped forms.
I've pushed your commit to a branch in this repo, to ensure we don't lose it for future reference in v4: https://github.com/mvdan/sh/tree/interp-handler-fs Sounds like we can close this, and go back to reviewing your original PR. Thanks again! |
BTW while doing this, it did cross my mind that perhaps it would be cleaner to just put all the different OS interactions behind a single type Sandbox interface {
Open(ctx context.Context, path string, flag int, perm os.FileMode) (io.ReadWriteCloser, error)
ReadDir(ctx context.Context, path string) ([]fs.DirEntry, error)
Stat(ctx context.Context, path string) (fs.FileInfo, error)
Exec(ctx context.Context, args []string) error
Call(ctx context.Context, args []string) ([]string, error)
} |
I haven't added any tests yet, this is just a first pass to see if this
is a good idea.
I converted all the obvious filesystem I could find that made sense.
There are a few issues though: