go_zipper/compress.go

185 lines
6.2 KiB
Go

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
}