Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion app.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,9 @@ func (a *App) initializeMenu() {

// View menu
ViewMenu := AppMenu.AddSubmenu("View")
ViewMenu.AddText("Sync Scroll Position", keys.Combo("e", keys.ShiftKey, keys.CmdOrCtrlKey), func(cd *menu.CallbackData) {})
ViewMenu.AddText("Sync Scroll Position", keys.Combo("e", keys.ShiftKey, keys.CmdOrCtrlKey), func(cd *menu.CallbackData) {
runtime.EventsEmit(a.ctx, string(entities.ActionToggleSyncScrollPosition))
})

// Scan menu
ScanMenu := AppMenu.AddSubmenu("Scan")
Expand Down
8 changes: 4 additions & 4 deletions backend/entities/keyboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ const (
ActionReplaceComponentWithComments Action = "replaceComponentWithComments"

// View
ActionSyncScrollPosition Action = "toggleSyncScrollPosition"
ActionToggleSyncScrollPosition Action = "toggleSyncScrollPosition"
ActionShowKeyboardShortcutsModal Action = "showKeyboardShortcutsModal"

// Scan
Expand Down Expand Up @@ -105,7 +105,7 @@ var AllShortcutActions = []struct {
{ActionReplaceFileWithComments, "ReplaceFileWithComments"},
{ActionReplaceComponentWithoutComments, "ReplaceComponentWithoutComments"},
{ActionReplaceComponentWithComments, "ReplaceComponentWithComments"},
{ActionSyncScrollPosition, "ToggleSyncScrollPosition"},
{ActionToggleSyncScrollPosition, "ToggleSyncScrollPosition"},
{ActionShowKeyboardShortcutsModal, "ShowKeyboardShortcutsModal"},
{ActionScanWithOptions, "ScanWithOptions"},
}
Expand Down Expand Up @@ -296,8 +296,8 @@ var DefaultShortcuts = []Shortcut{
Description: "Sync the scroll position of the editors",
Accelerator: keys.Combo("e", keys.ShiftKey, keys.CmdOrCtrlKey),
Keys: "shift+mod+e",
Group: GroupActions,
Action: ActionReplaceComponentWithComments,
Group: GroupView,
Action: ActionToggleSyncScrollPosition,
},

// Scan
Expand Down
18 changes: 5 additions & 13 deletions backend/entities/result.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ var (
)

type Result struct {
Path string `json:"path"`
MatchType string `json:"match_type"`
Purl *[]string `json:"purl,omitempty"`
ComponentName string `json:"component"`
Matches []Match `json:"matches,omitempty"`
Path string `json:"path"`
MatchType string `json:"match_type"`
Purl *[]string `json:"purl,omitempty"`
ComponentName string `json:"component"`
Matches []Component `json:"matches,omitempty"`
}

func NewResult() *Result {
Expand Down Expand Up @@ -96,14 +96,6 @@ type ResultLicense struct {
URL string `json:"url,omitempty"`
}

type Match struct {
ID string `json:"id"`
Purl []string `json:"purl,omitempty"`
ComponentName string `json:"component"`
Matched string `json:"matched,omitempty"`
Licenses []ResultLicense `json:"licenses,omitempty"`
}

type MatchType string

const (
Expand Down
86 changes: 64 additions & 22 deletions backend/mappers/result_mapper_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ package mappers

import (
"fmt"
"runtime"
"strings"
"sync"

"github.com/rs/zerolog/log"
purlutils "github.com/scanoss/go-purl-helper/pkg"
Expand All @@ -36,29 +38,52 @@ type ResultMapperImpl struct {
scanossSettings *entities.ScanossSettings
}

var (
resultDTOCache sync.Map
purlCache sync.Map
)

func NewResultMapper(scanossSettings *entities.ScanossSettings) ResultMapper {
return &ResultMapperImpl{
scanossSettings: scanossSettings,
}
}

func (m ResultMapperImpl) generateCacheKey(result entities.Result, bomEntry entities.ComponentFilter) string {
return fmt.Sprintf("%s-%s-%s-%s-%s-%s-%s",
result.Path,
strings.Join(*result.Purl, ","),
result.MatchType,
bomEntry.ReplaceWith,
bomEntry.Comment,
m.scanossSettings.SettingsFile.GetResultWorkflowState(result),
m.scanossSettings.SettingsFile.GetResultFilterConfig(result),
)
}

func (m ResultMapperImpl) MapToResultDTO(result entities.Result) entities.ResultDTO {
return entities.ResultDTO{
bomEntry := m.scanossSettings.SettingsFile.GetBomEntryFromResult(result)
cacheKey := m.generateCacheKey(result, bomEntry)

if cached, ok := resultDTOCache.Load(cacheKey); ok {
return cached.(entities.ResultDTO)
}

dto := entities.ResultDTO{
MatchType: entities.MatchType(result.MatchType),
Path: result.Path,
DetectedPurl: (*result.Purl)[0],
DetectedPurlUrl: m.mapDetectedPurlUrl(result),
ConcludedPurl: m.mapConcludedPurl(result),
ConcludedPurl: bomEntry.ReplaceWith,
ConcludedPurlUrl: m.mapConcludedPurlUrl(result),
ConcludedName: m.mapConcludedName(result),
WorkflowState: m.mapWorkflowState(result),
FilterConfig: m.mapFilterConfig(result),
Comment: m.mapComment(result),
Comment: bomEntry.Comment,
}
}

func (m ResultMapperImpl) mapComment(result entities.Result) string {
return m.scanossSettings.SettingsFile.GetBomEntryFromResult(result).Comment
resultDTOCache.Store(cacheKey, dto)
return dto
}

func (m ResultMapperImpl) mapConcludedPurl(result entities.Result) string {
Expand All @@ -67,11 +92,26 @@ func (m ResultMapperImpl) mapConcludedPurl(result entities.Result) string {

func (m ResultMapperImpl) MapToResultDTOList(results []entities.Result) []entities.ResultDTO {
output := make([]entities.ResultDTO, len(results))
numWorkers := runtime.NumCPU()
jobChan := make(chan int, len(results))
var wg sync.WaitGroup

for i, v := range results {
output[i] = m.MapToResultDTO(v)
for i := 0; i < len(results); i++ {
jobChan <- i
}
close(jobChan)

wg.Add(numWorkers)
for w := 0; w < numWorkers; w++ {
go func() {
defer wg.Done()
for idx := range jobChan {
output[idx] = m.MapToResultDTO(results[idx])
}
}()
}

wg.Wait()
return output
}

Expand Down Expand Up @@ -101,38 +141,40 @@ func (m *ResultMapperImpl) mapConcludedPurlUrl(result entities.Result) string {
purlName = fmt.Sprintf("%s/%s", purlObject.Namespace, purlObject.Name)
}

purlUrl, err := purlutils.ProjectUrl(purlName, purlObject.Type)
return m.getProjectURL(concludedPurl, func() (string, error) {
return purlutils.ProjectUrl(purlName, purlObject.Type)
})
}

func (m ResultMapperImpl) getProjectURL(purl string, compute func() (string, error)) string {
if cached, ok := purlCache.Load(purl); ok {
return cached.(string)
}
url, err := compute()
if err != nil {
log.Error().Err(err).Msg("Error getting project url")
log.Error().Err(err).Msg("Error computing project URL")
return ""
}

return purlUrl
purlCache.Store(purl, url)
return url
}

func (m ResultMapperImpl) mapDetectedPurlUrl(result entities.Result) string {
detectedPurl := (*result.Purl)[0]

purlObject, err := purlutils.PurlFromString(detectedPurl)

if err != nil {
log.Error().Err(err).Msg("Error parsing detected purl")
return ""
}

// Workaround for github purls until purlutils is updated
purlName := purlObject.Name
if purlObject.Type == "github" && purlObject.Namespace != "" {
purlName = fmt.Sprintf("%s/%s", purlObject.Namespace, purlObject.Name)
}

purlUrl, err := purlutils.ProjectUrl(purlName, purlObject.Type)
if err != nil {
log.Error().Err(err).Msg("Error getting detected purl url")
return ""
}

return purlUrl
return m.getProjectURL(detectedPurl, func() (string, error) {
return purlutils.ProjectUrl(purlName, purlObject.Type)
})
}

func (m ResultMapperImpl) mapConcludedName(result entities.Result) string {
Expand Down
20 changes: 7 additions & 13 deletions backend/repository/component_repository_json_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import (
"sort"

"github.com/scanoss/scanoss.cc/backend/entities"
"github.com/scanoss/scanoss.cc/internal/config"
"github.com/scanoss/scanoss.cc/internal/utils"
)

Expand All @@ -47,29 +46,24 @@ var licenseSourceOrder = map[string]int{
}

type JSONComponentRepository struct {
fr utils.FileReader
fr utils.FileReader
resultsRepository ResultRepository
}

func NewJSONComponentRepository(fr utils.FileReader) *JSONComponentRepository {
func NewJSONComponentRepository(fr utils.FileReader, resultsRepository ResultRepository) *JSONComponentRepository {
return &JSONComponentRepository{
fr: fr,
fr: fr,
resultsRepository: resultsRepository,
}
}

func (r *JSONComponentRepository) FindByFilePath(path string) (entities.Component, error) {
resultFilePath := config.GetInstance().GetResultFilePath()

resultFileBytes, err := r.fr.ReadFile(resultFilePath)
if err != nil {
return entities.Component{}, err
}
results, err := utils.JSONParse[map[string][]entities.Component](resultFileBytes)
result, err := r.resultsRepository.GetResultByPath(path)
if err != nil {
return entities.Component{}, err
}

// Gets components from results
components := results[path]
components := result.Matches

// Order component licenses by source
if len(components[0].Licenses) > 0 {
Expand Down
1 change: 1 addition & 0 deletions backend/repository/result_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,5 @@ import "github.com/scanoss/scanoss.cc/backend/entities"

type ResultRepository interface {
GetResults(filters entities.ResultFilter) ([]entities.Result, error)
GetResultByPath(path string) (entities.Result, error)
}
Loading
Loading