package archive import ( "archive/zip" "fmt" "io/ioutil" "os" "path/filepath" "sort" ) type ZipArchiver struct { filepath string filewriter *os.File writer *zip.Writer } func NewZipArchiver(filepath string) Archiver { return &ZipArchiver{ filepath: filepath, } } func (a *ZipArchiver) ArchiveContent(content []byte, infilename string) error { if err := a.open(); err != nil { return err } defer a.close() f, err := a.writer.Create(infilename) if err != nil { return err } _, err = f.Write(content) return err } func (a *ZipArchiver) ArchiveFile(infilename string) error { fi, err := assertValidFile(infilename) if err != nil { return err } content, err := ioutil.ReadFile(infilename) if err != nil { return err } return a.ArchiveContent(content, fi.Name()) } func (a *ZipArchiver) ArchiveDir(indirname string) error { _, err := assertValidDir(indirname) if err != nil { return err } if err := a.open(); err != nil { return err } defer a.close() return filepath.Walk(indirname, func(path string, info os.FileInfo, err error) error { if info.IsDir() { return nil } if err != nil { return err } relname, err := filepath.Rel(indirname, path) if err != nil { return fmt.Errorf("error relativizing file for archival: %s", err) } f, err := a.writer.Create(relname) if err != nil { return fmt.Errorf("error creating file inside archive: %s", err) } content, err := ioutil.ReadFile(path) if err != nil { return fmt.Errorf("error reading file for archival: %s", err) } _, err = f.Write(content) return err }) } func (a *ZipArchiver) ArchiveMultiple(content map[string][]byte) error { if err := a.open(); err != nil { return err } defer a.close() // Ensure files are processed in the same order so hashes don't change keys := make([]string, len(content)) i := 0 for k := range content { keys[i] = k i++ } sort.Strings(keys) for _, filename := range keys { f, err := a.writer.Create(filename) if err != nil { return err } _, err = f.Write(content[filename]) if err != nil { return err } } return nil } func (a *ZipArchiver) open() error { f, err := os.Create(a.filepath) if err != nil { return err } a.filewriter = f a.writer = zip.NewWriter(f) return nil } func (a *ZipArchiver) close() { if a.writer != nil { a.writer.Close() a.writer = nil } if a.filewriter != nil { a.filewriter.Close() a.filewriter = nil } }