add extract function, add roadmap and doc link
This commit is contained in:
parent
ad7dca46c7
commit
9cc659b973
4 changed files with 180 additions and 104 deletions
|
@ -1,6 +1,12 @@
|
||||||
# Archiver
|
# Archiver
|
||||||
A golang library for extracting and creating archives.
|
A golang library for extracting and creating archives.
|
||||||
|
|
||||||
|
[Documentation Link](https://pkg.go.dev/egtyl.xyz/omnibill/archiver)
|
||||||
|
|
||||||
|
## Roadmap
|
||||||
|
- [ ] Automatically detect the archive format
|
||||||
|
- [ ] Add mutexes to work with concurrency
|
||||||
|
|
||||||
## Supported Formats
|
## Supported Formats
|
||||||
- `.tar.gz`
|
- `.tar.gz`
|
||||||
- `.tar.bz2`
|
- `.tar.bz2`
|
||||||
|
|
114
archive_fs_test.go
Normal file
114
archive_fs_test.go
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
package archiver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"archive/tar"
|
||||||
|
"compress/gzip"
|
||||||
|
"github.com/go-git/go-billy/v5/memfs"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestArchiveFS(t *testing.T) {
|
||||||
|
err := os.MkdirAll(testArchiveBaseDir, os.ModePerm)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
memoryFS := memfs.New()
|
||||||
|
|
||||||
|
archiveF, err := memoryFS.OpenFile("archive.tar.gz", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, os.ModePerm)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
defer archiveF.Close()
|
||||||
|
|
||||||
|
gzipWriter := gzip.NewWriter(archiveF)
|
||||||
|
defer gzipWriter.Close()
|
||||||
|
|
||||||
|
tarWriter := tar.NewWriter(gzipWriter)
|
||||||
|
defer tarWriter.Close()
|
||||||
|
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
tarHeader := &tar.Header{
|
||||||
|
Name: "test" + strconv.Itoa(i) + ".txt",
|
||||||
|
Size: int64(len([]byte("Hello, World! #" + strconv.Itoa(i)))),
|
||||||
|
Mode: 0600,
|
||||||
|
}
|
||||||
|
err = tarWriter.WriteHeader(tarHeader)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = tarWriter.Write([]byte("Hello, World! #" + strconv.Itoa(i)))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = tarWriter.Close()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
err = gzipWriter.Close()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
err = archiveF.Close()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
t.Log("== OpenArchive ==")
|
||||||
|
archive, err := OpenFS(WrapBillyFS(memoryFS), TarGzip, "archive.tar.gz")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 10, archive.FileCount())
|
||||||
|
|
||||||
|
t.Log("== ExtractArchiveFile ==")
|
||||||
|
archiveFile, err := archive.GetFile("test0.txt")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = archiveFile.Extract(ExtractFileOptions{
|
||||||
|
Folder: testArchiveBaseDir + "/extracted/fs",
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = os.RemoveAll(testArchiveBaseDir + "/extracted/fs")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
t.Log("== ExtractArchive ==")
|
||||||
|
err = archive.Extract(ExtractOptions{
|
||||||
|
Folder: testArchiveBaseDir + "/extracted/fs",
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = os.RemoveAll(testArchiveBaseDir + "/extracted/fs")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
t.Log("== ExtractArchiveFilter ==")
|
||||||
|
err = archive.Extract(ExtractOptions{
|
||||||
|
Folder: testArchiveBaseDir + "/extracted/fs",
|
||||||
|
Filter: archiveRegex,
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.FileExists(t, testArchiveBaseDir+"/extracted/fs/test1.txt")
|
||||||
|
assert.FileExists(t, testArchiveBaseDir+"/extracted/fs/test5.txt")
|
||||||
|
|
||||||
|
err = os.RemoveAll(testArchiveBaseDir + "/extracted/fs")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = archive.Close()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExtractArchiveBillyFS(t *testing.T) {
|
||||||
|
err := os.MkdirAll(testArchiveBaseDir, os.ModePerm)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
testGenerateTar(t)
|
||||||
|
|
||||||
|
archive, err := Open(Tar, testArchiveBaseDir+"/test.tar")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
memoryFS := memfs.New()
|
||||||
|
|
||||||
|
err = archive.ExtractBillyFS(memoryFS, ExtractOptions{
|
||||||
|
Folder: memoryFS.Root(),
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
files, err := memoryFS.ReadDir(memoryFS.Root())
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, 10, len(files))
|
||||||
|
|
||||||
|
for _, file := range files {
|
||||||
|
assert.NotEqual(t, int64(0), file.Size())
|
||||||
|
}
|
||||||
|
}
|
146
archive_test.go
146
archive_test.go
|
@ -5,7 +5,6 @@ import (
|
||||||
"archive/zip"
|
"archive/zip"
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"github.com/dsnet/compress/bzip2"
|
"github.com/dsnet/compress/bzip2"
|
||||||
"github.com/go-git/go-billy/v5/memfs"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/ulikunitz/xz"
|
"github.com/ulikunitz/xz"
|
||||||
"os"
|
"os"
|
||||||
|
@ -20,6 +19,48 @@ const (
|
||||||
|
|
||||||
var archiveRegex = regexp.MustCompile(`(?m)test[1|5]`)
|
var archiveRegex = regexp.MustCompile(`(?m)test[1|5]`)
|
||||||
|
|
||||||
|
func TestArchiveExtract(t *testing.T) {
|
||||||
|
err := os.MkdirAll(testArchiveBaseDir, os.ModePerm)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
testGenerateZip(t)
|
||||||
|
testGenerateTar(t)
|
||||||
|
testGenerateTarXz(t)
|
||||||
|
testGenerateTarBzip(t)
|
||||||
|
TestArchiveTarGzip(t)
|
||||||
|
|
||||||
|
t.Log("== ExtractZip ==")
|
||||||
|
err = Extract(Zip, testArchiveBaseDir+"/test.zip", ExtractOptions{
|
||||||
|
Folder: testArchiveBaseDir + "/extracted/zip",
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
t.Log("== ExtractTar ==")
|
||||||
|
err = Extract(Tar, testArchiveBaseDir+"/test.tar", ExtractOptions{
|
||||||
|
Folder: testArchiveBaseDir + "/extracted/tar",
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
t.Log("== ExtractTarXz ==")
|
||||||
|
err = Extract(TarXz, testArchiveBaseDir+"/test.tar.xz", ExtractOptions{
|
||||||
|
Folder: testArchiveBaseDir + "/extracted/xz",
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
t.Log("== ExtractTarBz ==")
|
||||||
|
err = Extract(TarBzip, testArchiveBaseDir+"/test.tar.bz2", ExtractOptions{
|
||||||
|
Folder: testArchiveBaseDir + "/extracted/bzip",
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
t.Log("== ExtractTarGz ==")
|
||||||
|
err = Extract(TarGzip, testArchiveBaseDir+"/test.tar.gz", ExtractOptions{
|
||||||
|
Folder: testArchiveBaseDir + "/extracted/gz",
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func TestArchiveZip(t *testing.T) {
|
func TestArchiveZip(t *testing.T) {
|
||||||
err := os.MkdirAll(testArchiveBaseDir, os.ModePerm)
|
err := os.MkdirAll(testArchiveBaseDir, os.ModePerm)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
@ -252,109 +293,6 @@ func TestArchiveTar(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestArchiveFS(t *testing.T) {
|
|
||||||
err := os.MkdirAll(testArchiveBaseDir, os.ModePerm)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
memoryFS := memfs.New()
|
|
||||||
|
|
||||||
archiveF, err := memoryFS.OpenFile("archive.tar.gz", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, os.ModePerm)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
defer archiveF.Close()
|
|
||||||
|
|
||||||
gzipWriter := gzip.NewWriter(archiveF)
|
|
||||||
defer gzipWriter.Close()
|
|
||||||
|
|
||||||
tarWriter := tar.NewWriter(gzipWriter)
|
|
||||||
defer tarWriter.Close()
|
|
||||||
|
|
||||||
for i := 0; i < 10; i++ {
|
|
||||||
tarHeader := &tar.Header{
|
|
||||||
Name: "test" + strconv.Itoa(i) + ".txt",
|
|
||||||
Size: int64(len([]byte("Hello, World! #" + strconv.Itoa(i)))),
|
|
||||||
Mode: 0600,
|
|
||||||
}
|
|
||||||
err = tarWriter.WriteHeader(tarHeader)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
_, err = tarWriter.Write([]byte("Hello, World! #" + strconv.Itoa(i)))
|
|
||||||
assert.NoError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = tarWriter.Close()
|
|
||||||
assert.NoError(t, err)
|
|
||||||
err = gzipWriter.Close()
|
|
||||||
assert.NoError(t, err)
|
|
||||||
err = archiveF.Close()
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
t.Log("== OpenArchive ==")
|
|
||||||
archive, err := OpenFS(WrapBillyFS(memoryFS), TarGzip, "archive.tar.gz")
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, 10, archive.FileCount())
|
|
||||||
|
|
||||||
t.Log("== ExtractArchiveFile ==")
|
|
||||||
archiveFile, err := archive.GetFile("test0.txt")
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
err = archiveFile.Extract(ExtractFileOptions{
|
|
||||||
Folder: testArchiveBaseDir + "/extracted/fs",
|
|
||||||
})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
err = os.RemoveAll(testArchiveBaseDir + "/extracted/fs")
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
t.Log("== ExtractArchive ==")
|
|
||||||
err = archive.Extract(ExtractOptions{
|
|
||||||
Folder: testArchiveBaseDir + "/extracted/fs",
|
|
||||||
})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
err = os.RemoveAll(testArchiveBaseDir + "/extracted/fs")
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
t.Log("== ExtractArchiveFilter ==")
|
|
||||||
err = archive.Extract(ExtractOptions{
|
|
||||||
Folder: testArchiveBaseDir + "/extracted/fs",
|
|
||||||
Filter: archiveRegex,
|
|
||||||
})
|
|
||||||
|
|
||||||
assert.FileExists(t, testArchiveBaseDir+"/extracted/fs/test1.txt")
|
|
||||||
assert.FileExists(t, testArchiveBaseDir+"/extracted/fs/test5.txt")
|
|
||||||
|
|
||||||
err = os.RemoveAll(testArchiveBaseDir + "/extracted/fs")
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
err = archive.Close()
|
|
||||||
assert.NoError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestExtractArchiveBillyFS(t *testing.T) {
|
|
||||||
err := os.MkdirAll(testArchiveBaseDir, os.ModePerm)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
testGenerateTar(t)
|
|
||||||
|
|
||||||
archive, err := Open(Tar, testArchiveBaseDir+"/test.tar")
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
memoryFS := memfs.New()
|
|
||||||
|
|
||||||
err = archive.ExtractBillyFS(memoryFS, ExtractOptions{
|
|
||||||
Folder: memoryFS.Root(),
|
|
||||||
})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
files, err := memoryFS.ReadDir(memoryFS.Root())
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
assert.Equal(t, 10, len(files))
|
|
||||||
|
|
||||||
for _, file := range files {
|
|
||||||
assert.NotEqual(t, int64(0), file.Size())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func testGenerateTar(t *testing.T) {
|
func testGenerateTar(t *testing.T) {
|
||||||
tarFile, err := os.Create(testArchiveBaseDir + "/test.tar")
|
tarFile, err := os.Create(testArchiveBaseDir + "/test.tar")
|
||||||
defer tarFile.Close()
|
defer tarFile.Close()
|
||||||
|
|
18
open.go
18
open.go
|
@ -30,6 +30,24 @@ func Open(archiveType Type, path string) (*Archive, error) {
|
||||||
return openArchive(WrapPath(archiveFolderPath), archiveType, path)
|
return openArchive(WrapPath(archiveFolderPath), archiveType, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extract opens an archive file and extracts the contents.
|
||||||
|
// It takes a Type, a path, and ExtractOptions for its parameters.
|
||||||
|
// The function returns an error, if any.
|
||||||
|
func Extract(archiveType Type, path string, options ExtractOptions) error {
|
||||||
|
archiveFile, err := Open(archiveType, path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer archiveFile.Close()
|
||||||
|
if err := archiveFile.Extract(options); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := archiveFile.Close(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func openArchive(filesystem Filesystem, archiveType Type, path string) (*Archive, error) {
|
func openArchive(filesystem Filesystem, archiveType Type, path string) (*Archive, error) {
|
||||||
archive := new(Archive)
|
archive := new(Archive)
|
||||||
archive.files = make(map[string]*File)
|
archive.files = make(map[string]*File)
|
||||||
|
|
Loading…
Reference in a new issue