dive/dive/filetree/comparer.go
Alex Goodman d5e8a92968
Rework CI validation workflow and makefile (#460)
* rework CI validation workflow and makefile

* enable push

* fix job names

* fix license check

* fix snapshot builds

* fix acceptance tests

* fix linting

* disable pull request event

* rework windows runner caching

* disable release pipeline and add issue templates
2023-07-06 22:01:46 -04:00

175 lines
4.7 KiB
Go

package filetree
import (
"fmt"
"github.com/sirupsen/logrus"
)
type TreeIndexKey struct {
bottomTreeStart, bottomTreeStop, topTreeStart, topTreeStop int
}
func NewTreeIndexKey(bottomTreeStart, bottomTreeStop, topTreeStart, topTreeStop int) TreeIndexKey {
return TreeIndexKey{
bottomTreeStart: bottomTreeStart,
bottomTreeStop: bottomTreeStop,
topTreeStart: topTreeStart,
topTreeStop: topTreeStop,
}
}
func (index TreeIndexKey) String() string {
if index.bottomTreeStart == index.bottomTreeStop && index.topTreeStart == index.topTreeStop {
return fmt.Sprintf("Index(%d:%d)", index.bottomTreeStart, index.topTreeStart)
} else if index.bottomTreeStart == index.bottomTreeStop {
return fmt.Sprintf("Index(%d:%d-%d)", index.bottomTreeStart, index.topTreeStart, index.topTreeStop)
} else if index.topTreeStart == index.topTreeStop {
return fmt.Sprintf("Index(%d-%d:%d)", index.bottomTreeStart, index.bottomTreeStop, index.topTreeStart)
}
return fmt.Sprintf("Index(%d-%d:%d-%d)", index.bottomTreeStart, index.bottomTreeStop, index.topTreeStart, index.topTreeStop)
}
type Comparer struct {
refTrees []*FileTree
trees map[TreeIndexKey]*FileTree
pathErrors map[TreeIndexKey][]PathError
}
func NewComparer(refTrees []*FileTree) Comparer {
return Comparer{
refTrees: refTrees,
trees: make(map[TreeIndexKey]*FileTree),
pathErrors: make(map[TreeIndexKey][]PathError),
}
}
func (cmp *Comparer) GetPathErrors(key TreeIndexKey) ([]PathError, error) {
_, pathErrors, err := cmp.get(key)
if err != nil {
return nil, err
}
return pathErrors, nil
}
func (cmp *Comparer) GetTree(key TreeIndexKey) (*FileTree, error) {
// func (cmp *Comparer) GetTree(bottomTreeStart, bottomTreeStop, topTreeStart, topTreeStop int) (*FileTree, []PathError, error) {
// key := TreeIndexKey{bottomTreeStart, bottomTreeStop, topTreeStart, topTreeStop}
if value, exists := cmp.trees[key]; exists {
return value, nil
}
value, pathErrors, err := cmp.get(key)
if err != nil {
return nil, err
}
cmp.trees[key] = value
cmp.pathErrors[key] = pathErrors
return value, nil
}
func (cmp *Comparer) get(key TreeIndexKey) (*FileTree, []PathError, error) {
newTree, pathErrors, err := StackTreeRange(cmp.refTrees, key.bottomTreeStart, key.bottomTreeStop)
if err != nil {
return nil, nil, err
}
for idx := key.topTreeStart; idx <= key.topTreeStop; idx++ {
markPathErrors, err := newTree.CompareAndMark(cmp.refTrees[idx])
pathErrors = append(pathErrors, markPathErrors...)
if err != nil {
logrus.Errorf("error while building tree: %+v", err)
return nil, nil, err
}
}
return newTree, pathErrors, nil
}
// case 1: layer compare (top tree SIZE is fixed (BUT floats forward), Bottom tree SIZE changes)
func (cmp *Comparer) NaturalIndexes() <-chan TreeIndexKey {
indexes := make(chan TreeIndexKey)
go func() {
defer close(indexes)
var bottomTreeStart, bottomTreeStop, topTreeStart, topTreeStop int
for selectIdx := 0; selectIdx < len(cmp.refTrees); selectIdx++ {
bottomTreeStart = 0
topTreeStop = selectIdx
if selectIdx == 0 {
bottomTreeStop = selectIdx
topTreeStart = selectIdx
} else {
bottomTreeStop = selectIdx - 1
topTreeStart = selectIdx
}
indexes <- TreeIndexKey{
bottomTreeStart: bottomTreeStart,
bottomTreeStop: bottomTreeStop,
topTreeStart: topTreeStart,
topTreeStop: topTreeStop,
}
}
}()
return indexes
}
// case 2: aggregated compare (bottom tree is ENTIRELY fixed, top tree SIZE changes)
func (cmp *Comparer) AggregatedIndexes() <-chan TreeIndexKey {
indexes := make(chan TreeIndexKey)
go func() {
defer close(indexes)
var bottomTreeStart, bottomTreeStop, topTreeStart, topTreeStop int
for selectIdx := 0; selectIdx < len(cmp.refTrees); selectIdx++ {
bottomTreeStart = 0
topTreeStop = selectIdx
if selectIdx == 0 {
bottomTreeStop = selectIdx
topTreeStart = selectIdx
} else {
bottomTreeStop = 0
topTreeStart = 1
}
indexes <- TreeIndexKey{
bottomTreeStart: bottomTreeStart,
bottomTreeStop: bottomTreeStop,
topTreeStart: topTreeStart,
topTreeStop: topTreeStop,
}
}
}()
return indexes
}
func (cmp *Comparer) BuildCache() (errors []error) {
for index := range cmp.NaturalIndexes() {
pathError, _ := cmp.GetPathErrors(index)
if len(pathError) > 0 {
for _, path := range pathError {
errors = append(errors, fmt.Errorf("path error at layer index %s: %s", index, path))
}
}
_, err := cmp.GetTree(index)
if err != nil {
errors = append(errors, err)
return errors
}
}
for index := range cmp.AggregatedIndexes() {
_, err := cmp.GetTree(index)
if err != nil {
errors = append(errors, err)
return errors
}
}
return errors
}