package zipper import ( "fmt" "io" "os" ) type Writer interface { Flush() error Close() error } type Compressor interface { Compress(fileToZip *os.File, pathInArchive string) (err error) OpenWriter(zipFile *os.File) (err error) MultiFileSupported() bool } // zipper defines a struct for a Zip-file writer type zipper struct { filename string zipFile *os.File zipWriter Writer isOpen bool compressor Compressor canCompress bool } type Zipper interface { io.Closer AddZipFilesPathed(files []string, pathInArchive, pathInFileSystem string) error AddZipFiles(files []string, pathInArchive string) error AddZipFilesPathedSimple(files []string, pathInFileSystem string) error AddZipFilesSimple(files []string) error AddFileToZipPathed(filename, pathInArchive, pathInFileSystem string) error AddFileToZip(filename, pathInArchive string) error AddFileToZipPathedSimple(filename, pathInFileSystem string) error AddFileToZipSimple(filename string) error SetCompressor(compressor Compressor) error SetWriter(writer Writer) GetWriter() (writer Writer) } // NewBaseZipper makes a new Zipper interface missing the compressor. func NewBaseZipper(archiveFilename string) Zipper { return &zipper{filename: archiveFilename, isOpen: false, canCompress: true} } func (zipper *zipper) SetCompressor(compressor Compressor) (err error) { if compressor != nil { if zipper.compressor == nil { zipper.compressor = compressor } else { err = fmt.Errorf("compressor already defined") } } else { err = fmt.Errorf("undefined compressor") } return } func (zipper *zipper) SetWriter(writer Writer) { zipper.zipWriter = writer } func (zipper *zipper) GetWriter() Writer { return zipper.zipWriter } // Close implements the Closer interface func (zipper *zipper) Close() (err error) { if zipper.isOpen { if nil != zipper.zipWriter { zipper.zipWriter.Flush() if err = zipper.zipWriter.Close(); err == nil { zipper.zipWriter = nil } } if nil == err && nil != zipper.zipFile { zipper.zipFile.Sync() if err = zipper.zipFile.Close(); err == nil { zipper.zipFile = nil } } if err == nil { zipper.isOpen = false } } return } // AddZipFilesPathed compresses one or many files into the current zip archive file. // Param 1: files is a list of files to add to the zip. // Param 2: pathInArchive is subfolder definition within the zip, where the files are to be situated. // Param 3: pathInFileSystem is the subfolder definition within the file system, where the file may be found. func (zipper *zipper) AddZipFilesPathed(files []string, pathInArchive, pathInFileSystem string) (err error) { // Add files to zip for _, file := range files { if err = zipper.AddFileToZipPathed(file, pathInArchive, pathInFileSystem); err != nil { break } } return err } // AddZipFiles compresses one or many files into the current zip archive file. // Param 1: files is a list of files to add to the zip. // Param 2: pathInArchive is subfolder definition within the zip, where the files are to be situated. func (zipper *zipper) AddZipFiles(files []string, pathInArchive string) error { return zipper.AddZipFilesPathed(files, pathInArchive, "") } // AddZipFilesPathedSimple compresses one or many files into the current zip archive file. // Param 1: files is a list of files to add to the zip. // Param 2: pathInFileSystem is the subfolder definition within the file system, where the file may be found. func (zipper *zipper) AddZipFilesPathedSimple(files []string, pathInFileSystem string) error { return zipper.AddZipFilesPathed(files, "", pathInFileSystem) } // AddZipFilesSimple compresses one or many files into the current zip archive file. // Param: files is a list of files to add to the zip. func (zipper *zipper) AddZipFilesSimple(files []string) error { return zipper.AddZipFilesPathed(files, "", "") } // AddFileToZip compresses a single file into the current zip archive file. // Param 1: filename reflects the path of the file to add to the zip within the file system. // Param 2: pathInArchive is the subfolder definition within the zip, where the file is to be situated. func (zipper *zipper) AddFileToZip(filename, pathInArchive string) error { return zipper.AddFileToZipPathed(filename, pathInArchive, "") } // AddFileToZipPathedSimple compresses a single file into the current zip archive file. // Param 1: filename reflects the path of the file to add to the zip within the file system. // Param 2: pathInFileSystem is the subfolder definition within the file system, where the file may be found. func (zipper *zipper) AddFileToZipPathedSimple(filename, pathInFileSystem string) error { return zipper.AddFileToZipPathed(filename, "", pathInFileSystem) } // AddFileToZipSimple compresses a single file into the current zip archive file. // Param: filename reflects the path of the file to add to the zip within the file system. func (zipper *zipper) AddFileToZipSimple(filename string) error { return zipper.AddFileToZipPathed(filename, "", "") } // AddFileToZipPathed compresses a single file into the current zip archive file. // Param 1: filename reflects the path of the file to add to the zip within the file system. // Param 2: pathInArchive is the subfolder definition within the zip, where the file is to be situated. // Param 3: pathInFileSystem is the subfolder definition within the file system, where the file may be found. func (zipper *zipper) AddFileToZipPathed(filename, pathInArchive, pathInFileSystem string) (err error) { if zipper.compressor == nil { return fmt.Errorf("unable to initialise compressor") } if !zipper.isOpen { if err = MakeSurePathExists(zipper.filename, 0644); err == nil { if zipper.zipFile, err = os.Create(zipper.filename); err == nil { err = zipper.compressor.OpenWriter(zipper.zipFile) zipper.isOpen = true } } } if nil != err { return err } if !zipper.canCompress { return fmt.Errorf("no further compression is supported") } var fileToZip *os.File if fileToZip, err = os.Open(PrependPath(filename, pathInFileSystem)); err != nil { return err } defer fileToZip.Close() if err = zipper.compressor.Compress(fileToZip, pathInArchive); err == nil { if !zipper.compressor.MultiFileSupported() { zipper.canCompress = false } } return err }