package archiver import ( "archive/zip" "fmt" "io" "os" "path/filepath" "github.com/atomaka/collect/collector" ) // ZipArchiver creates zip archives type ZipArchiver struct{} // NewZipArchiver creates a new zip archiver func NewZipArchiver() *ZipArchiver { return &ZipArchiver{} } // Create creates a zip archive with the collected files func (a *ZipArchiver) 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 zip writer zipWriter := zip.NewWriter(outFile) defer zipWriter.Close() // Add each file to the archive for _, file := range files { if err := a.addFileToZip(zipWriter, file); err != nil { return fmt.Errorf("failed to add file %s: %w", file.Path, err) } } return nil } // addFileToZip adds a single file to the zip archive func (a *ZipArchiver) addFileToZip(zw *zip.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 zip file header header, err := zip.FileInfoHeader(info) if err != nil { return err } // Use the relative path in the archive header.Name = filepath.ToSlash(file.Path) // Set compression method header.Method = zip.Deflate // Create writer for this file writer, err := zw.CreateHeader(header) if err != nil { return err } // Copy file contents _, err = io.Copy(writer, f) return err }