package bundle import ( "archive/zip" "context" "io" "os" "path/filepath" "strings" "github.com/pkg/errors" "gitlab.com/wpetit/goweb/logger" ) type ZipBundle struct { reader *zip.Reader } func (b *ZipBundle) File(filename string) (io.ReadCloser, os.FileInfo, error) { ctx := logger.With( context.Background(), logger.F("filename", filename), ) logger.Debug(ctx, "opening file") f, err := b.reader.Open(filename) if err != nil { return nil, nil, errors.WithStack(err) } stat, err := f.Stat() if err != nil { return nil, nil, errors.WithStack(err) } return f, stat, nil } func (b *ZipBundle) Dir(dirname string) ([]os.FileInfo, error) { files := make([]os.FileInfo, 0) ctx := context.Background() for _, f := range b.reader.File { if !strings.HasPrefix(f.Name, dirname) { continue } relPath, err := filepath.Rel(dirname, f.Name) if err != nil { return nil, errors.Wrap(err, "could not get relative path") } logger.Debug( ctx, "checking file prefix", logger.F("dirname", dirname), logger.F("filename", f.Name), logger.F("relpath", relPath), ) if relPath == filepath.Base(f.Name) { files = append(files, f.FileInfo()) } } return files, nil } func NewZipBundleFromReader(reader io.ReaderAt, size int64) (*ZipBundle, error) { zipReader, err := zip.NewReader(reader, size) if err != nil { return nil, errors.WithStack(err) } return &ZipBundle{ reader: zipReader, }, nil } func NewZipBundleFromPath(filename string) (*ZipBundle, error) { file, err := os.Open(filename) if err != nil { return nil, errors.WithStack(err) } stat, err := file.Stat() if err != nil { return nil, errors.WithStack(err) } return NewZipBundleFromReader(file, stat.Size()) } func Must(bundle Bundle, err error) Bundle { if err != nil { panic(errors.WithStack(err)) } return bundle }