diff --git a/api/analysis.go b/api/analysis.go index d04d7c6e0..459581996 100644 --- a/api/analysis.go +++ b/api/analysis.go @@ -2270,6 +2270,7 @@ func (r *ReportWriter) db() (db *gorm.DB) { // // Write builds and streams the analysis report. func (r *ReportWriter) Write(id uint) { + reportDir := Settings.Analysis.ReportPath path, err := r.buildOutput(id) if err != nil { _ = r.ctx.Error(err) @@ -2282,6 +2283,9 @@ func (r *ReportWriter) Write(id uint) { defer func() { tarWriter.Close() }() + filter := tar.NewFilter(reportDir) + filter.Exclude("output.js") + tarWriter.Filter = filter err = tarWriter.AssertDir(Settings.Analysis.ReportPath) if err != nil { _ = r.ctx.Error(err) diff --git a/api/bucket.go b/api/bucket.go index 2ca45908f..42d4c0934 100644 --- a/api/bucket.go +++ b/api/bucket.go @@ -231,10 +231,8 @@ func (h *BucketOwner) bucketGet(ctx *gin.Context, id uint) { return } if st.IsDir() { - filter := tar.Filter{ - Pattern: ctx.Query(Filter), - Root: path, - } + filter := tar.NewFilter(path) + filter.Include(ctx.Query(Filter)) if h.Accepted(ctx, binding.MIMEHTML) { h.getFile(ctx, m) } else { diff --git a/tar/filter.go b/tar/filter.go index 36b683fe3..63fdd5a1c 100644 --- a/tar/filter.go +++ b/tar/filter.go @@ -5,28 +5,105 @@ import ( "path/filepath" ) +// +// NewFilter returns a filter. +func NewFilter(root string) (f Filter) { + f = Filter{Root: root} + return +} + // // Filter supports glob-style filtering. type Filter struct { - Root string - Pattern string - cache map[string]bool + included FilterSet + excluded FilterSet + Root string } // // Match determines if path matches the filter. func (r *Filter) Match(path string) (b bool) { - if r.Pattern == "" { - b = true + r.included.root = r.Root + r.excluded.root = r.Root + if r.included.Len() > 0 { + included := r.included.Match(path) + if !included { + return + } + } + b = true + if r.excluded.Len() > 0 { + excluded := r.excluded.Match(path) + if excluded { + b = false + return + } + } + return +} + +// +// Include adds included patterns. +// Empty ("") patterns are ignored. +func (r *Filter) Include(patterns ...string) { + r.included.Add(patterns...) +} + +// +// Exclude adds excluded patterns. +// Empty ("") patterns are ignored. +func (r *Filter) Exclude(patterns ...string) { + r.excluded.Add(patterns...) +} + +// +// FilterSet is a collection of filter patterns. +type FilterSet struct { + root string + patterns []string + cache map[string]bool +} + +// +// Match returns true when the path matches. +func (r *FilterSet) Match(path string) (match bool) { + r.build() + _, match = r.cache[path] + return +} + +// +// Add pattern. +// Empty ("") patterns are ignored. +func (r *FilterSet) Add(patterns ...string) { + for _, p := range patterns { + if p == "" { + continue + } + r.cache = nil + r.patterns = append( + r.patterns, + p) + } +} + +// +// Len returns number of patterns. +func (r *FilterSet) Len() (n int) { + return len(r.patterns) +} + +// +// build populates the cache as needed. +func (r *FilterSet) build() { + if r.cache != nil { return } - if r.cache == nil { - r.cache = map[string]bool{} - matches, _ := filepath.Glob(pathlib.Join(r.Root, r.Pattern)) + r.cache = make(map[string]bool) + for i := range r.patterns { + matches, _ := filepath.Glob(pathlib.Join(r.root, r.patterns[i])) for _, p := range matches { r.cache[p] = true } } - _, b = r.cache[path] - return }