package archiver import ( "archive/tar" "compress/gzip" "fmt" "io" "os" "path/filepath" "github.com/atomaka/collect/collector" ) // TarArchiver creates tar.gz archives type TarArchiver struct{} // NewTarArchiver creates a new tar archiver func NewTarArchiver() *TarArchiver { return &TarArchiver{} } // Create creates a tar.gz archive with the collected files func (a *TarArchiver) Create(outputPath string, files []collector.FileEntry) error { // Create output file outFile, err := os.Create(outputPath) if err != nil { return fmt.Errorf("failed to create output file: %w", err) } defer outFile.Close() // Create gzip writer gzipWriter := gzip.NewWriter(outFile) defer gzipWriter.Close() // Create tar writer tarWriter := tar.NewWriter(gzipWriter) defer tarWriter.Close() // Add each file to the archive for _, file := range files { if err := a.addFileToTar(tarWriter, file); err != nil { return fmt.Errorf("failed to add file %s: %w", file.Path, err) } } return nil } // addFileToTar adds a single file to the tar archive func (a *TarArchiver) addFileToTar(tw *tar.Writer, file collector.FileEntry) error { // Open the file f, err := os.Open(file.FullPath) if err != nil { // Skip files we can't read with a warning if os.IsPermission(err) { fmt.Fprintf(os.Stderr, "Warning: Cannot read file: %s\n", file.FullPath) return nil } return err } defer f.Close() // Get file info info, err := f.Stat() if err != nil { return err } // Create tar header header, err := tar.FileInfoHeader(info, "") if err != nil { return err } // Use the relative path in the archive header.Name = filepath.ToSlash(file.Path) // Write header if err := tw.WriteHeader(header); err != nil { return err } // Copy file contents _, err = io.Copy(tw, f) return err }