-
Notifications
You must be signed in to change notification settings - Fork 380
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
Proposal: io/fs presents us an opportunity to rework the whole api into a v2 #407
Comments
@puellanivis I'm interested to improve the This is my plan for the
I'm not sure how we can improve the request interfaces, they already seem well designed. If we want to change them we should do it in a way that does not require to checking if an interface is implemented for each packet (for example for writes). Do you already have some sort of draft? The V6 support is a long term plan, I have other priorities for now, I think I can work on this after releasing SFTPGo 2.1 |
Well, as mentioned above, the current Client targets a different FS object interface than does the new standard library FS defines. Many of the distinctions are probably small, like I don’t think it would be a good idea to jump straight into reimplementing the server or client, as it would probably be better to get a solid baseline done first, like a wire protocol package, and maybe a memfs. The former would then allow us to build on top of to get a good client+server, while the later helps define really what we would expect the implementations themselves to look like. It might be most nice to have both the client and server both look quite parallel themselves, and both of them try to model after the |
Re: reworking sftp.Client, it can be made more compatible maybe, but full compatibility severely restricts the client's ability to talk to arbitrary servers. io/fs.FS wants the Open method to validate paths using fs.ValidPath. That requires the path to be "UTF-8-encoded, unrooted, slash-separated sequences of path elements", which may not contain Skipping the validation is possible, but leads to surprising behavior when trying to use a Client as an fs.FS: type unvalidatingFS struct{}
func (unvalidatingFS) Open(path string) (fs.File, error) {
return nil, nil
}
func main() {
var fsys fs.FS = unvalidatingFS{}
_, err := fsys.Open("../shouldnt/work/but/does")
fmt.Println(err)
// <nil>
fsys, err = fs.Sub(fsys, "foo")
if err != nil {
panic(err)
}
_, err = fsys.Open("../doesnt/work")
fmt.Println(err)
// Here, fs.Sub's Open has done the validation that we skipped, and we get:
// open ../doesnt/work: invalid name
} |
Indeed, I am expecting that this wouldn’t be 100% Note, if you add this receiver method, the second one won’t error anymore:
Though TL;DR: I agree, we don’t want to restrict ourselves too heavily onto P.S.: I mean, first and foremost, right now the |
I started some experiments here: https://github.com/parro-it/vs/tree/master/sshfs, in case someone would take a look at it. In my (probably simplistic) implementation you can just call |
Doing path.Clean is not a sufficient replacement. If /a/b/c is a symlink to /d/c, then /a/b/c/.. is /d, not /a/b. |
Good point, I always found that thing really annoying... anyway, I'm not saying that |
I mean, it should be relatively simple for us to provide a built-in wrapper to provide an P.S.: I don’t think we should just tack this onto the current implementation though, while this feature would be a super nice feature to add in, there are a lot of other points calling for making a breaking-change API update. I mean, just alone being able to clean up the public surface would be great. |
@puellanivis I agree with you, that totally makes sense... |
I still don't see the benefit of moving halfway to io/fs, but if a v2 is on the table, I do have a proposal to make. Please tell me if this should be a separate issue, but I'd like suggest that in v2, normaliseError be changed so that StatusErrors are returned as-is, and that type gets the following method: // Is implements errors.Is's interface, matching s against os.ErrExist,
// os.ErrNotExist and os.ErrPermission.
func (s *StatusError) Is(err error) bool {
switch s.Code {
case sshFxFileAlreadyExists:
return err == os.ErrExist
case sshFxNoSuchFile:
return err == os.ErrNotExist
case sshFxPermissionDenied:
return err == os.ErrPermission
}
return false
} Right now, errors are changed in backward-incompatible ways even in minor releases (#401). With a publicly documented Is method, that need not happen again and all errors retain full details of what caused them. |
The benefits of moving “halfway to io/fs” are in improved API parallelism. We don’t need to rely upon Random Peron’s The greater reasons for a new API are that there are tons of improvements that could be made throughout the code base considering the newer features of the language, like |
I didn't mean to be polemical :) Re: random person's design, I thought kr/fs was pretty popular, but looking at https://pkg.go.dev/github.com/kr/fs?tab=importedby it looks like many of the importers are in fact clones of pkg/sftp. So it looks like little is lost in dropping it and, say, returning []io/fs.DirEntry from ReadDir. I also see the broader benefit of a v2. Having a perm argument to OpenFile and Mkdir would also be great. |
Most of the proposal is right there in the title. What with
io/fs
being rolled out in go1.16, we have a big opportunity to remodel, simplify, and rework our API. Current issues, as I see them:sftp.Client
implementsgithub.com/kr/fs
, but we could switch to model more compatible withio/fs.FS
ErrSshFxXyz
errors are still around, because they cannot be removed without a breaking change.RequestServer
andServer
implementations are significantly different and almost parallel implementations.RequestServer
could be better implemented via a base interface with additional extension interfaces. (à laio/fs
)allocator
?) or dropped entirely (we could switchWriteTo
so that it does not depend upon filesizes, thus saving us the need of anUseFstat()
option).The text was updated successfully, but these errors were encountered: