Skip to content

Commit

Permalink
manifest file with markers.
Browse files Browse the repository at this point in the history
Signed-off-by: Jeff Ortel <jortel@redhat.com>
  • Loading branch information
jortel committed Aug 12, 2024
1 parent 9080894 commit 32f4c5f
Show file tree
Hide file tree
Showing 3 changed files with 182 additions and 95 deletions.
197 changes: 154 additions & 43 deletions api/analysis.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package api

import (
"bufio"
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"os"
"regexp"
"sort"
"strconv"
"strings"
Expand Down Expand Up @@ -315,7 +318,7 @@ func (h AnalysisHandler) AppList(ctx *gin.Context) {
// @description - dependencies: file that multiple api.TechDependency resources.
// @tags analyses
// @produce json
// @success 201 {object} api.AnalysisManifest
// @success 201 {object} api.Ref
// @router /application/{id}/analyses [post]
// @param id path int true "Application ID"
func (h AnalysisHandler) AppCreate(ctx *gin.Context) {
Expand All @@ -332,50 +335,72 @@ func (h AnalysisHandler) AppCreate(ctx *gin.Context) {
return
}
}
//
// Analysis
manifest := &AnalysisManifest{}
err := h.Bind(ctx, manifest)
if err != nil {
_ = ctx.Error(err)
return
}
r := Analysis{}
r.Commit = manifest.Commit
analysis := r.Model()
analysis.ApplicationID = id
analysis.CreateUser = h.BaseHandler.CurrentUser(ctx)
db := h.DB(ctx)
db.Logger = db.Logger.LogMode(logger.Error)
err = db.Create(analysis).Error
//
// Manifest
ref := &Ref{}
err := h.Bind(ctx, ref)
if err != nil {
_ = ctx.Error(err)
return
}
//
// Issues
file := &model.File{}
err = db.First(file, manifest.Issues.ID).Error
err = db.First(file, ref.ID).Error
if err != nil {
err = &BadRequestError{err.Error()}
_ = ctx.Error(err)
return
}
reader, err := os.Open(file.Path)
reader := &AnalysisReader{}
f, err := reader.open(
file.Path,
"___BEGIN-ANALYSIS___",
"___END-ANALYSIS___")
if err != nil {
err = &BadRequestError{err.Error()}
_ = ctx.Error(err)
return
}
defer func() {
_ = reader.Close()
_ = f.Close()
}()
d, err := h.Decoder(ctx, file.Encoding, reader)
if err != nil {
err = &BadRequestError{err.Error()}
_ = ctx.Error(err)
return
}
r := &Analysis{}
err = d.Decode(r)
if err != nil {
err = &BadRequestError{err.Error()}
_ = ctx.Error(err)
return
}
analysis := r.Model()
analysis.ApplicationID = id
analysis.CreateUser = h.BaseHandler.CurrentUser(ctx)
db.Logger = db.Logger.LogMode(logger.Error)
err = db.Create(analysis).Error
if err != nil {
_ = ctx.Error(err)
return
}
//
// Issues
reader = &AnalysisReader{}
f, err = reader.open(
file.Path,
"___BEGIN-ISSUES___",
"___END-ISSUES___")
if err != nil {
err = &BadRequestError{err.Error()}
_ = ctx.Error(err)
return
}
defer func() {
_ = f.Close()
}()
for {
r := &Issue{}
err = d.Decode(r)
Expand All @@ -399,28 +424,19 @@ func (h AnalysisHandler) AppCreate(ctx *gin.Context) {
}
//
// Dependencies
file = &model.File{}
err = db.First(file, manifest.Dependencies.ID).Error
if err != nil {
err = &BadRequestError{err.Error()}
_ = ctx.Error(err)
return
}
reader, err = os.Open(file.Path)
reader = &AnalysisReader{}
f, err = reader.open(
file.Path,
"___BEGIN-DEPENDENCIES___",
"___END-DEPENDENCIES___")
if err != nil {
err = &BadRequestError{err.Error()}
_ = ctx.Error(err)
return
}
defer func() {
_ = reader.Close()
_ = f.Close()
}()
d, err = h.Decoder(ctx, file.Encoding, reader)
if err != nil {
err = &BadRequestError{err.Error()}
_ = ctx.Error(err)
return
}
var deps []*TechDependency
for {
r := &TechDependency{}
Expand Down Expand Up @@ -2345,13 +2361,6 @@ type DepAppReport struct {
} `json:"dependency"`
}

// AnalysisManifest resource.
type AnalysisManifest struct {
Commit string `json:"commit,omitempty" yaml:",omitempty"`
Issues Ref `json:"issues"`
Dependencies Ref `json:"dependencies"`
}

// FactMap map.
type FactMap map[string]any

Expand Down Expand Up @@ -2858,3 +2867,105 @@ func (r *yamlEncoder) embed(object any) encoder {
r.write(s)
return r
}

// AnalysisReader manifest reader.
type AnalysisReader struct {
file *os.File
marker map[string]int64
begin int64
end int64
read int64
}

// scan manifest and catalog position of markers.
func (r *AnalysisReader) scan(path string) (err error) {
if r.marker != nil {
return
}
r.file, err = os.Open(path)
if err != nil {
return
}
defer func() {
_ = r.file.Close()
}()
pattern, err := regexp.Compile(`^___[A-Z-]+___$`)
if err != nil {
return
}
p := int64(0)
r.marker = make(map[string]int64)
scanner := bufio.NewScanner(r.file)
for scanner.Scan() {
content := scanner.Text()
content = strings.TrimSpace(content)
if pattern.Match([]byte(content)) {
r.marker[content] = p
}
p += int64(len(content))
p++
}

return
}

// open returns a read delimited by the specified markers.
func (r *AnalysisReader) open(path, begin, end string) (reader io.ReadCloser, err error) {
found := false
err = r.scan(path)
if err != nil {
return
}
r.begin, found = r.marker[begin]
if !found {
err = &BadRequestError{
Reason: fmt.Sprintf("marker: %s not found.", begin),
}
return
}
r.end, found = r.marker[end]
if !found {
err = &BadRequestError{
Reason: fmt.Sprintf("marker: %s not found.", end),
}
return
}
if r.begin >= r.end {
err = &BadRequestError{
Reason: fmt.Sprintf("marker: %s must preceed %s.", begin, end),
}
return
}
r.begin = r.begin + int64(len(begin))
r.begin += 1
r.read = r.end - r.begin
r.file, err = os.Open(path)
if err != nil {
return
}
_, err = r.file.Seek(r.begin, io.SeekStart)
reader = r
return
}

// Read bytes.
func (r *AnalysisReader) Read(b []byte) (n int, err error) {
n, err = r.file.Read(b)
if n == 0 || err != nil {
return
}
if int64(n) > r.read {
n = int(r.read)
}
r.read -= int64(n)
if n < 1 {
err = io.EOF
}
return
}

// Close the reader.
func (r *AnalysisReader) Close() (err error) {
err = r.file.Close()
return
}
17 changes: 4 additions & 13 deletions binding/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ type Analysis struct {
// as individual documents.
// The `deps` is the path to a file containing api.TechDependency(s)
// as individual documents.
func (h *Analysis) Create(commit, encoding, issues, deps string) (err error) {
func (h *Analysis) Create(manifest, encoding string) (err error) {
switch encoding {
case "":
encoding = binding.MIMEJSON
Expand All @@ -331,26 +331,17 @@ func (h *Analysis) Create(commit, encoding, issues, deps string) (err error) {
"Encoding: %s not supported",
encoding)
}
r := &api.AnalysisManifest{Commit: commit}
file := File{client: h.client}
f, err := file.PostEncoded(issues, encoding)
f, err := file.PostEncoded(manifest, encoding)
if err != nil {
return
}
r.Issues = api.Ref{ID: f.ID}
defer func() {
_ = file.Delete(f.ID)
}()
f, err = file.PostEncoded(deps, encoding)
if err != nil {
return
}
r.Dependencies = api.Ref{ID: f.ID}
ref := &api.Ref{ID: f.ID}
defer func() {
_ = file.Delete(f.ID)
}()
path := Path(api.AppAnalysesRoot).Inject(Params{api.ID: h.appId})
err = h.client.Post(path, r)
err = h.client.Post(path, ref)
if err != nil {
return
}
Expand Down
Loading

0 comments on commit 32f4c5f

Please sign in to comment.