Files
distributor/pkg/upload/archive.go

105 lines
2.8 KiB
Go

package upload
import (
"archive/tar"
"bytes"
"compress/gzip"
"fmt"
"io"
"os"
"path/filepath"
"time"
"gitea.maximumdirect.net/eric/distributor/pkg/bundle"
)
func archiveBundle(root string, manifest bundle.Manifest) ([]byte, error) {
var output bytes.Buffer
gzipWriter := gzip.NewWriter(&output)
tarWriter := tar.NewWriter(gzipWriter)
manifestData, err := bundle.MarshalManifest(manifest)
if err != nil {
return nil, err
}
if err := writeTarEntry(tarWriter, bundle.ManifestName, manifestData, 0o600, manifest.Created); err != nil {
_ = tarWriter.Close()
_ = gzipWriter.Close()
return nil, err
}
for _, manifestFile := range manifest.Files {
fullPath := filepath.Join(root, filepath.FromSlash(manifestFile.Path))
info, err := os.Lstat(fullPath)
if err != nil {
_ = tarWriter.Close()
_ = gzipWriter.Close()
return nil, fmt.Errorf("file %q stat: %w", manifestFile.Path, err)
}
if !info.Mode().IsRegular() {
_ = tarWriter.Close()
_ = gzipWriter.Close()
return nil, fmt.Errorf("file %q must be a regular file", manifestFile.Path)
}
file, err := os.Open(fullPath)
if err != nil {
_ = tarWriter.Close()
_ = gzipWriter.Close()
return nil, fmt.Errorf("file %q open: %w", manifestFile.Path, err)
}
if err := writeTarFile(tarWriter, manifestFile.Path, file, info.Mode().Perm(), info.ModTime(), info.Size()); err != nil {
_ = file.Close()
_ = tarWriter.Close()
_ = gzipWriter.Close()
return nil, err
}
if err := file.Close(); err != nil {
_ = tarWriter.Close()
_ = gzipWriter.Close()
return nil, fmt.Errorf("file %q close: %w", manifestFile.Path, err)
}
}
if err := tarWriter.Close(); err != nil {
_ = gzipWriter.Close()
return nil, fmt.Errorf("close tar archive: %w", err)
}
if err := gzipWriter.Close(); err != nil {
return nil, fmt.Errorf("close gzip archive: %w", err)
}
return output.Bytes(), nil
}
func writeTarEntry(writer *tar.Writer, name string, data []byte, mode int64, modTime time.Time) error {
header := &tar.Header{
Name: name,
Mode: mode,
Size: int64(len(data)),
ModTime: modTime,
}
if err := writer.WriteHeader(header); err != nil {
return fmt.Errorf("write tar header %q: %w", name, err)
}
if _, err := writer.Write(data); err != nil {
return fmt.Errorf("write tar entry %q: %w", name, err)
}
return nil
}
func writeTarFile(writer *tar.Writer, name string, file *os.File, mode os.FileMode, modTime time.Time, size int64) error {
if mode == 0 {
mode = 0o600
}
header := &tar.Header{
Name: name,
Mode: int64(mode),
Size: size,
ModTime: modTime,
}
if err := writer.WriteHeader(header); err != nil {
return fmt.Errorf("write tar header %q: %w", name, err)
}
if _, err := io.Copy(writer, file); err != nil {
return fmt.Errorf("write tar entry %q: %w", name, err)
}
return nil
}