-
Notifications
You must be signed in to change notification settings - Fork 83
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
Document how to override file modification times to zero via http.FileSystem wrapper. #31
Comments
Hey @ZoltanLajosKis, thanks for great feedback.
Glad to hear this package's API is being appreciated for that! I, too, enjoy that very much. I have two high level answers to your problem that I want to share and ask what you think:
First, it's possible to solve the problem without adding a special case to You're saying you want custom behavior for how to handle zero value type modTimeFS struct {
fs http.FileSystem
}
func (fs modTimeFS) Open(name string) (http.File, error) {
f, err := fs.fs.Open(name)
if err != nil {
return nil, err
}
return modTimeFile{f}, nil
}
type modTimeFile struct {
http.File
}
func (f modTimeFile) Stat() (os.FileInfo, error) {
fi, err := f.File.Stat()
if err != nil {
return nil, err
}
if fi.ModTime().IsZero() {
// ... insert the custom logic you want to deal with zero mod time here
}
return fi, nil
} This is the beauty and power of orthogonal interfaces. I wanted to point out the above because it's possible. However, I don't neccessary recommend you actually use this, because I have a better suggestion. I think the better solution here is to avoid dropping information. By using I suspect you're using fs := New(map[string]string{
"foo/bar/three.txt": "a",
"foo/bar.txt": "b",
"top.txt": "c",
"other-top.txt": "d",
})
I think that's the way to go. I've created similar utilities that work with Specifically, see I use it significantly in all my projects for this purpose. E.g.: What do you think? Do you agree that it's not necessary to modify |
I understand your point, and now I agree that ModTime should be opaque for vfsgen. I did not consider the possibility that other people might actually want to rely on this, e.g., to disable HTTP caching (perhaps this commenter meant something like that). It is just inconvenient that while generating the assets code, none of the components' API mention explicitly that using zero ModTime means HTTP caching will be disabled in th end.
Yes, you got me there. I created go-assets to collect assets from multiple locations and compile them to code with vfsgen. Although I not only collect from the file system, but also from HTTP endpoints; and also extract files selectively from archives. Here is an example usage: https://github.com/ZoltanLajosKis/gmdd/blob/master/generate/assets.go#L12
That looks nice. I did consider keeping the File descriptors around instead of pulling everything into memory. But the amount of indirections (vfsgen referring to asset referring to archive referring to http request) seemed too complex for resource management and error propagation. Perhaps it's time to revisit with the http.FileSystem interface in mind? :-)
I agree, no change is necessary. I will leave it up to you whether you think this issue is worth documenting in Usage, around the |
I'm interested in improving documentation. Reopening for that. However, can you clarify which issue specifically you had in mind? |
I'll also mention that in the comparison section, I wrote:
You said:
That's really cool. I want to think a bit more about that. I think you're using vfsgen in exactly the way I anticipated, so if it's not scaling well for that kind of use, I want to better understand why.
Do you mind elaborating a bit on that? What do you mean by revisiting the I suspect that some of the challenges you're mentioning are because you're trying to convert from |
Serving
I meant that perhaps I should revisit my design and use http.FileSystem as the intermediary interface across processing steps. Tar.gz extraction could be modeled to take a single file from one file system and provide another file system with the archived files in it. A HTTP request could be modeled to provide a file system with a single file in it. Checksum verification could be modeled to take an input file system and provide an output file system with the same files; but return error on Open if there is a checksum mismatch. I just need to better understand how resource management would look like here. For example, does tar.gz extraction reopen the input file whenever one output file is accessed? Or does it keep the input file descriptor open (and if so, when does it close it?) Or does it read the archive on creation and cache all archived files in memory? Etc. |
First of all, thanks for this great package. I love the simplicity and clarity of using httpfs as both the input and the output interface.
Currently vfsgen copies the file modification time (ModTime) value from the input httpfs to the output httpfs as is, even if it is set to zero value. When the built-in HTTP file server encounters a zero time in the file system, it omits the
Last-Modified
header, which disables client-side caching.This problem is apparent when using go's mapfs and httpfs to provide vfsgen input. The mapfs package always uses zero value as ModTime, so the HTTP file server will never include cache control headers.
To reproduce, generate a file system using the above packages...
... serve the generated file system ...
... and verify that no cache control headers as sent.
I would suggest to handle zero value ModTime as a special case in vfsgen. As a simple fix, zero values could replaced with the
time.Now()
value. This would enable client-side caching, even across server restarts (but not across rebuilds).As an alternative solution I have created a modified mapfs, go-mapfs, which takes both the file contents and the file modification time as input. This way the true modification time can be preserved and caching will work even across rebuilds.
The text was updated successfully, but these errors were encountered: