init
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
package archiver
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// Create creates a tar.gz archive from the given files relative to rootDir
|
||||
// Returns: archive reader, archive size, error
|
||||
func Create(files []string, rootDir string) (io.Reader, int64, error) {
|
||||
var buf bytes.Buffer
|
||||
gzWriter := gzip.NewWriter(&buf)
|
||||
tarWriter := tar.NewWriter(gzWriter)
|
||||
|
||||
for _, file := range files {
|
||||
// Get full path
|
||||
fullPath := filepath.Join(rootDir, file)
|
||||
|
||||
// Open file
|
||||
f, err := os.Open(fullPath)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to open file %s: %w", file, err)
|
||||
}
|
||||
|
||||
// Get file info
|
||||
info, err := f.Stat()
|
||||
if err != nil {
|
||||
f.Close()
|
||||
return nil, 0, fmt.Errorf("failed to stat file %s: %w", file, err)
|
||||
}
|
||||
|
||||
// Create tar header
|
||||
header := &tar.Header{
|
||||
Name: file, // Use relative path
|
||||
Size: info.Size(),
|
||||
Mode: int64(info.Mode()),
|
||||
ModTime: info.ModTime(),
|
||||
}
|
||||
|
||||
// Write header
|
||||
if err := tarWriter.WriteHeader(header); err != nil {
|
||||
f.Close()
|
||||
return nil, 0, fmt.Errorf("failed to write tar header for %s: %w", file, err)
|
||||
}
|
||||
|
||||
// Write file content
|
||||
if _, err := io.Copy(tarWriter, f); err != nil {
|
||||
f.Close()
|
||||
return nil, 0, fmt.Errorf("failed to write file content for %s: %w", file, err)
|
||||
}
|
||||
|
||||
f.Close()
|
||||
}
|
||||
|
||||
// Close tar writer
|
||||
if err := tarWriter.Close(); err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to close tar writer: %w", err)
|
||||
}
|
||||
|
||||
// Close gzip writer
|
||||
if err := gzWriter.Close(); err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to close gzip writer: %w", err)
|
||||
}
|
||||
|
||||
size := int64(buf.Len())
|
||||
return &buf, size, nil
|
||||
}
|
||||
|
||||
// Extract extracts a tar.gz archive to the destination directory
|
||||
// Returns: list of extracted files, error
|
||||
func Extract(archive io.Reader, destDir string) ([]string, error) {
|
||||
// Create gzip reader
|
||||
gzReader, err := gzip.NewReader(archive)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create gzip reader: %w", err)
|
||||
}
|
||||
defer gzReader.Close()
|
||||
|
||||
// Create tar reader
|
||||
tarReader := tar.NewReader(gzReader)
|
||||
|
||||
var extractedFiles []string
|
||||
|
||||
for {
|
||||
header, err := tarReader.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read tar header: %w", err)
|
||||
}
|
||||
|
||||
// Get target path
|
||||
targetPath := filepath.Join(destDir, header.Name)
|
||||
|
||||
// Ensure directory exists
|
||||
dir := filepath.Dir(targetPath)
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
return nil, fmt.Errorf("failed to create directory %s: %w", dir, err)
|
||||
}
|
||||
|
||||
// Create file
|
||||
f, err := os.OpenFile(targetPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(header.Mode))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create file %s: %w", targetPath, err)
|
||||
}
|
||||
|
||||
// Copy content
|
||||
if _, err := io.Copy(f, tarReader); err != nil {
|
||||
f.Close()
|
||||
return nil, fmt.Errorf("failed to write file content for %s: %w", targetPath, err)
|
||||
}
|
||||
|
||||
f.Close()
|
||||
extractedFiles = append(extractedFiles, header.Name)
|
||||
}
|
||||
|
||||
return extractedFiles, nil
|
||||
}
|
||||
|
||||
// List lists files in the archive without extracting
|
||||
func List(archive io.Reader) ([]string, error) {
|
||||
// Create gzip reader
|
||||
gzReader, err := gzip.NewReader(archive)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create gzip reader: %w", err)
|
||||
}
|
||||
defer gzReader.Close()
|
||||
|
||||
// Create tar reader
|
||||
tarReader := tar.NewReader(gzReader)
|
||||
|
||||
var files []string
|
||||
|
||||
for {
|
||||
header, err := tarReader.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read tar header: %w", err)
|
||||
}
|
||||
|
||||
files = append(files, header.Name)
|
||||
}
|
||||
|
||||
return files, nil
|
||||
}
|
||||
Reference in New Issue
Block a user