* 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
175 lines
4.7 KiB
Go
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
|
|
}
|