- Initial commit.
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
package gzip
|
||||
|
||||
import (
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
zipper "git.sa-roci.de/oss/go_zipper"
|
||||
)
|
||||
|
||||
const ArchiveExt = ".gz"
|
||||
|
||||
// NewZipper makes a new Zipper.
|
||||
func NewGZipper(gzipFilename string, multiFile bool) zipper.Zipper {
|
||||
if !strings.HasSuffix(strings.ToLower(gzipFilename), ArchiveExt) {
|
||||
gzipFilename += ArchiveExt
|
||||
}
|
||||
gzipper := gZipper{
|
||||
Zipper: zipper.NewBaseZipper(gzipFilename),
|
||||
multiFile: multiFile,
|
||||
}
|
||||
gzipper.SetCompressor(&gzipper)
|
||||
return gzipper
|
||||
}
|
||||
|
||||
type gZipper struct {
|
||||
zipper.Zipper
|
||||
output io.Writer
|
||||
multiFile bool
|
||||
}
|
||||
|
||||
func (gz *gZipper) OpenWriter(zipFile *os.File) error {
|
||||
gz.SetWriter(gzip.NewWriter(zipFile))
|
||||
gz.output = zipFile
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gz *gZipper) MultiFileSupported() bool {
|
||||
return gz.multiFile
|
||||
}
|
||||
|
||||
func (gz *gZipper) Compress(fileToZip *os.File, pathInArchive string) (err error) {
|
||||
// Get the file information
|
||||
var info fs.FileInfo
|
||||
if info, err = fileToZip.Stat(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
filename := info.Name()
|
||||
|
||||
if writer, ok := gz.GetWriter().(*gzip.Writer); ok {
|
||||
writer.ModTime = info.ModTime()
|
||||
|
||||
// Using FileInfoHeader() above only uses the basename of the file. If we want
|
||||
// to preserve the folder structure we can overwrite this with the full path.
|
||||
if len(pathInArchive) > 0 || strings.Contains(filename, "/") || strings.Contains(filename, "\\") {
|
||||
writer.Name = zipper.PrependPath(filename, pathInArchive)
|
||||
} else {
|
||||
writer.Name = filename
|
||||
}
|
||||
|
||||
if _, err = io.Copy(writer, fileToZip); err == nil {
|
||||
flushErr := writer.Flush()
|
||||
if err = writer.Close(); err != nil {
|
||||
err = flushErr
|
||||
} else {
|
||||
writer.Reset(gz.output)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("unable to access compressor")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package gzip
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const (
|
||||
content = "test-content"
|
||||
)
|
||||
|
||||
func TestZipper(t *testing.T) {
|
||||
archiveFolder := "testdata"
|
||||
archiveFilename := archiveFolder + "/dummy"
|
||||
testFileName := "testZipper.data"
|
||||
if os.WriteFile(testFileName, []byte(content), 0644) == nil {
|
||||
defer os.Remove(testFileName)
|
||||
}
|
||||
z := NewGZipper(archiveFilename, true)
|
||||
if z.GetWriter() != nil {
|
||||
t.Log("Found unexpected writer")
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
// Test adding files
|
||||
if z.AddZipFiles([]string{testFileName}, "testfolder") != nil {
|
||||
t.Log("Unable to add a single file")
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
// Test adding more files than allowed
|
||||
if z.AddFileToZip(testFileName, "testfolder/more") != nil {
|
||||
t.Log("Unexpectedly failed in adding more than one file")
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
z.Close()
|
||||
|
||||
uz := NewGUnzipper(archiveFilename + ArchiveExt)
|
||||
|
||||
if uz.ExtractFiles("") != nil {
|
||||
t.Log("Failed to extract files")
|
||||
t.Fail()
|
||||
} else {
|
||||
if data, err := os.ReadFile("testfolder/" + testFileName); err != nil {
|
||||
t.Log("Expected extracted file #1 is missing")
|
||||
t.Fail()
|
||||
} else if string(data) != content {
|
||||
t.Logf("Unexpected extracted file #1 content: '%s'", string(data))
|
||||
t.Fail()
|
||||
}
|
||||
if data, err := os.ReadFile("testfolder/more/" + testFileName); err != nil {
|
||||
t.Log("Expected extracted file #2 is missing")
|
||||
t.Fail()
|
||||
} else if string(data) != content {
|
||||
t.Logf("Unexpected extracted file #2 content: '%s'", string(data))
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up
|
||||
removeRecursive("testfolder")
|
||||
os.Remove(archiveFilename + ArchiveExt)
|
||||
os.Remove(archiveFolder)
|
||||
}
|
||||
|
||||
func removeRecursive(path string) {
|
||||
filepath.Walk(path, deleteFiles)
|
||||
filepath.WalkDir(path, deleteFolders)
|
||||
filepath.WalkDir(path, deleteFolders)
|
||||
filepath.WalkDir(path, deleteFolders)
|
||||
}
|
||||
|
||||
func deleteFiles(path string, info fs.FileInfo, errIn error) (err error) {
|
||||
if errIn != nil {
|
||||
return
|
||||
}
|
||||
if !info.IsDir() {
|
||||
err = os.Remove(path)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func deleteFolders(path string, info fs.DirEntry, errIn error) (err error) {
|
||||
if errIn != nil {
|
||||
return
|
||||
}
|
||||
os.Remove(path)
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package gzip
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
zipper "git.sa-roci.de/oss/go_zipper"
|
||||
)
|
||||
|
||||
// NewGUnzipper makes a new Unzipper.
|
||||
func NewGUnzipper(zipFilename string) zipper.Unzipper {
|
||||
guz := gUnzipper{
|
||||
Unzipper: zipper.NewBaseUnzipper(zipFilename),
|
||||
}
|
||||
guz.SetDecompressor(&guz)
|
||||
return guz
|
||||
}
|
||||
|
||||
type gUnzipper struct {
|
||||
zipper.Unzipper
|
||||
buffer bytes.Buffer
|
||||
}
|
||||
|
||||
func (guz *gUnzipper) OpenReader(zipFile *os.File) (err error) {
|
||||
var reader *gzip.Reader
|
||||
guz.buffer = bytes.Buffer{}
|
||||
if _, err = io.Copy(&guz.buffer, zipFile); err == nil {
|
||||
if reader, err = gzip.NewReader(&guz.buffer); err == nil {
|
||||
guz.SetReader(reader)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (guz *gUnzipper) Decompress(targetFolderPathInFileSystem string) (err error) {
|
||||
if reader, ok := guz.GetReader().(*gzip.Reader); ok {
|
||||
if err = zipper.MakeSurePathExists(targetFolderPathInFileSystem+"/dummy.file", 0644); err == nil {
|
||||
for {
|
||||
if reader.Name == "" {
|
||||
break
|
||||
}
|
||||
reader.Multistream(false)
|
||||
outputPath := zipper.PrependPath(reader.Name, targetFolderPathInFileSystem)
|
||||
if err = zipper.MakeSurePathExists(outputPath, 0644); err == nil {
|
||||
var dstFile *os.File
|
||||
if dstFile, err = os.OpenFile(outputPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644); err == nil {
|
||||
defer dstFile.Close()
|
||||
if _, err = io.Copy(dstFile, reader); err == nil {
|
||||
if err = reader.Reset(&guz.buffer); err == io.EOF {
|
||||
err = nil
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
Reference in New Issue
Block a user