Skip to content

Commit

Permalink
🐛 Fix HTML analysis report. (konveyor#513)
Browse files Browse the repository at this point in the history
The HTML report (tarball) is composed/streamed by the hub in steps:
1. Add the static report directory (template).
2. Add the composed `output.js` file which contains the analysis data.

Using this method, the ReportWriter was adding the `output.js` (entry)
twice in the tar. First from the static report (template) and the second
generated by the hub.
The tar command line seems to deal with this by overwriting the file.
However the _extract_ functionality used by browsers ignores the 2nd
occurrence.

The fix is to filter out the 1st output.js when using
tar.Writer.AddDir().

The `Filter` in the `tar` package only supported _include_ filtering.
This PR updates the `tar.Filter` to support both _included_ and
_excluded_ patterns.

Refitted and tested the /bucket.

---------

Signed-off-by: Jeff Ortel <jortel@redhat.com>
  • Loading branch information
jortel authored and aufi committed Oct 30, 2023
1 parent 855f10d commit 20a0875
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 14 deletions.
4 changes: 4 additions & 0 deletions api/analysis.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down
6 changes: 2 additions & 4 deletions api/bucket.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
97 changes: 87 additions & 10 deletions tar/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

0 comments on commit 20a0875

Please sign in to comment.