-
Notifications
You must be signed in to change notification settings - Fork 17.8k
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
archive/zip: add (*Writer).AddFS #54898
Comments
This doesn't look like something that belongs in fsys := os.DirFS("src")
zw := zip.NewWriter(w)
defer zw.Close()
fs.WalkDir(fsys, ".", func(p string, d fs.DirEntry, err error) error {
if err != nil || d.IsDir() {
return err
}
zf, _ := zw.Create(p)
f, _ := fsys.Open(p)
defer f.Close()
_, _ = io.Copy(zf, f)
}) |
How about a way to simply hand zw := zip.NewWriter(w)
defer zw.Close()
err := zw.AddFS(os.DirFS("src"))
// ... |
Adding to DeedleFake's proposal, perhaps |
@carlmjohnson if we want a filter, AddFS(fsys fs.FS, filters ...func(string) (bool, error)) error Seems like the more flexible solution. |
I completely forgot about Using @DeedleFake's proposed Regarding filtering the files to include, I can see this going two ways.
I have rewritten my proposal pseudo-code below to use // AddFS creates a zip archive of a directory by writing files from f to w.
func (w *Writer) AddFS (f fs.FS) (err error) {
err = fs.WalkDir(f, ".", func(path string, d fs.DirEntry, err error) error {
// Error with path.
if err != nil {
return err
}
// Skip directories. Directories will be created automatically from paths to
// each file to zip up.
if d.IsDir() {
return nil
}
// Handle formatting path name properly for use in zip file. Paths must
// use forward slashes, even on Windows.
// See: https://pkg.go.dev/archive/zip#Writer.Create
//
// Directories are created automatically based on the subdirectories provided
// in each file's path.
path = filepath.ToSlash(path)
// Open the path to read from.
f, err := f.Open(path)
if err != nil {
return err
}
defer f.Close()
// Create the file in the zip.
w, err := w.Create(path)
if err != nil {
return err
}
// Write the source file into the zip at path noted in Create().
_, err = io.Copy(w, f)
if err != nil {
return err
}
return nil
})
if err != nil {
return
}
return
} |
If filter is a callback, you don't need to take multiple. Just take one and people can write any filter chaining themselves: |
Maybe this would be useful as a more generalized wrapper for the |
there's https://pkg.go.dev/io/fs#Glob |
But that just returns a |
I think we should just skip the "filtering files to zip" functionality altogether and just zip an entire If a user doesn't want certain files to be zipped, then they can manually write the code to filter and zip, or remove the file(s) from the directory to be zipped. |
@seankhliao Using FS.Glob seems like the right idea, indeed. But one can write an FS that filters files internally, so the benefits are debatable. |
I think it's worth it to have some mechanism to filter because otherwise in those cases, you end up with a lot of boilerplate, which is the motivation for this issue. I still think matches, err := fs.Glob(fsys, "*.txt")
if err != nil { /**/ }
zw := zip.NewWriter(w)
defer zw.Close()
err := zw.AddFS(fsys, matches)
The benefit is that making a new FS is a lot of boilerplate. It would be nice though if the fs package had more mechanisms for cut down FSes, beside just fs.Sub. |
Would the availability of a ready-to-use implementation of I'm not sure if the concern is "no such filesystem implementation exists yet", "such a filesystem would be impossible to implement robustly in practice", or "the need to use such a filesystem makes this too inconvenient". The latter two would perhaps be justification for building filtering in to the zip API, but the former seems more like justification for a separate proposal to extend the When I read "an FS that filters files internally" I imagine an API allowing something like the following:
Is that too much boilerplate? Or is it that the |
It's not clear to me what a good signature for fs.FilterFS would be. |
Pardon my abruptness, but I feel we are going off on quite a tangent with this whole "filtering as |
How do we proceed with this? Do I need to write a formal proposal for this? If we are really interested in implementing a filtering mechanism, we can simply just copy the implementation of |
My sense is that we are discussing the possibility of generally filtering filesystems because it it's an important part of deciding whether the I would agree that the exact details of how the general feature might work are not really relevant to the proposal, but whether such a thing would be possible/desirable at all does seem to be material to this proposal, unless you (as the original proposer) would like to explicitly rule out filtering as being in scope for what you are proposing. I personally think that would be fine; anyone who considers filtering to be a crucial component could then create a parallel proposal for that. I'm not Go team but since I'm already replying anyway: my sense of the proposals process is that this issue has already been classified as a proposal and so it's in the right state to be visible to the proposal review group. The proposal review group will therefore at some point review this and discuss whether there seems to be a developing consensus. If not, they may ask further questions to try to encourage such consensus. Other commenters here are currently attempting to help refine the proposal by clarifying the requirements and non-requirements, and discussing some different implementation/design approaches. In other proposal issues the original proposer typically responds to that by either incorporating the feedback into the original proposal text or clarifying exactly what is in scope for the proposal as far as they are concerned. There is a short doc on The Proposal Process. My sense is that this issue is currently in the early stages of step 2, where others are trying to help develop the proposal in preparation for the proposal group to "triage the proposal". |
Hello All, |
This is in the incoming queue for proposal review. I'll bump its priority. |
This proposal has been added to the active column of the proposals project |
It sounds like the minimal addition would be
and then if you want more filtering or changing of paths or metadata, you write an fs.FS that does that. The implementation of this is also fairly straightforward. In common use
Do I have that right? edit added error result |
@rsc Yes, that is exactly what I was thinking. Any filtering would be handled before calling I'm sure you meant it, but I think you would also want to |
That sounds strange to me, like it's creating an FS. Maybe |
The Create family all return io.Writers. I don't think this fits that pattern. |
@DeedleFake Yes, I know it sounds weird. I just figured we should be following the naming convention. @carlmjohnson I do see that the "Create" family all return io.Writer. So "AddFS" it is I guess. |
Leaving likely accept for #58000 to catch up. |
No change in consensus, so accepted. 🎉 |
Sorry I'm late to the party. The I apologize for bikeshedding, but if we Possible suggestions:
|
|
I don't think we want the Also, how would this work for the equivalent of |
If we are worried about the f, _ := os.Create(pathToZipFile)
zw := zip.NewWriter(f)
defer zw.Close()
sourceDir := os.DirFS(pathToDirectory)
err := zw.FS(sourceDir)
if err != nil {
//handle err
} Another naming could be |
I don't see how |
|
Hello, have there been any progress on this or the related |
The method AddFS can be used to add the contents of a fs.FS filesystem to a zip archive. This method walks the directory tree starting at the root of the filesystem and adds each file to the archive. Fixes: golang#54898
Change https://go.dev/cl/513438 mentions this issue: |
Zipping a directory is unclear and slightly confusing via the
archive/zip
package, mostly due to the way paths need to be handled and how directories are created. I suggest adding a func to handle zipping a directory simply to aid in implementation. I have had to implement, or educate others on implementing, similar code for various projects over the years. Furthermore, help via StackOverflow, golang-nuts, etc., isn't very clear either. There is clearly somewhat wide-spread confusion regarding zipping a directory.Pseudo-code is below.
The text was updated successfully, but these errors were encountered: