Skip to content

Commit

Permalink
Merge branch 'release/v0.14.1' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
nhinze23 authored and cesmarvin committed Oct 17, 2024
2 parents 607453e + ef9bd19 commit df7982a
Show file tree
Hide file tree
Showing 7 changed files with 925 additions and 210 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [v0.14.1] - 2024-10-17
### Changed
- use topological sorting to sort dogus by dependency

### Deprecated
- `SortDogusByDependency`: Use `SortDogusByDependencyWithError` instead for better error handling
- `SortDogusByInvertedDependency`: Use `SortDogusByInvertedDependencyWithError` instead for better error handling

## [v0.14.0] - 2024-09-18
### Changed
- Relicense to AGPL-3.0-only (#40)
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Set these to the desired values
ARTIFACT_ID=cesapp-lib
VERSION=0.14.0
VERSION=0.14.1

GOTAG?=1.18.6
MAKEFILES_VERSION=7.4.0
Expand Down
126 changes: 83 additions & 43 deletions core/dogu-sort.go
Original file line number Diff line number Diff line change
@@ -1,28 +1,55 @@
package core

import (
"fmt"
"github.com/gammazero/toposort"
"sort"
)

// SortDogusByDependency takes an unsorted slice of Dogu structs and returns a slice of Dogus ordered by the
// importance of their dependencies descending, that is: the most needed dogu will be the first element.
//
// Deprecated: This function returns nil on error. For better error-handling use SortDogusByDependencyWithError instead.
//
//goland:noinspection GoDeprecation
func SortDogusByDependency(dogus []*Dogu) []*Dogu {
orderedDogus, _ := SortDogusByDependencyWithError(dogus)
return orderedDogus
}

// SortDogusByDependencyWithError takes an unsorted slice of Dogu structs and returns a slice of Dogus ordered by the
// importance of their dependencies descending, that is: the most needed dogu will be the first element.
func SortDogusByDependencyWithError(dogus []*Dogu) ([]*Dogu, error) {
ordered := sortByDependency{dogus}
sort.Stable(&ordered)
return ordered.dogus
orderedDogus, err := ordered.sortDogusByDependency()
if err != nil {
err = fmt.Errorf("error in sorting dogus by dependency: %s", err)
log.Error(err)
}
return orderedDogus, err
}

// SortDogusByInvertedDependency takes an unsorted slice of Dogu structs and returns a new slice of Dogus ordered by the
// importance of their dependencies ascending, that is: the most independent dogu will be the first element.
//
// Deprecated: This function returns nil on error. For better error-handling use SortDogusByInvertedDependencyWithError instead.
//
//goland:noinspection GoDeprecation
func SortDogusByInvertedDependency(dogus []*Dogu) []*Dogu {
orderedDesc := SortDogusByDependency(dogus)
orderedDogus, _ := SortDogusByInvertedDependencyWithError(dogus)
return orderedDogus
}

orderedAsc := []*Dogu{}
for i := len(orderedDesc) - 1; i >= 0; i-- {
orderedAsc = append(orderedAsc, dogus[i])
// SortDogusByInvertedDependencyWithError takes an unsorted slice of Dogu structs and returns a new slice of Dogus ordered by the
// importance of their dependencies ascending, that is: the most independent dogu will be the first element.
func SortDogusByInvertedDependencyWithError(dogus []*Dogu) ([]*Dogu, error) {
ordered := sortByDependency{dogus}
orderedDogus, err := ordered.sortDogusByInvertedDependency()
if err != nil {
err = fmt.Errorf("error in sorting dogus by inverted dependency: %s", err)
log.Error(err)
}

return orderedAsc
return orderedDogus, err
}

// SortDogusByName takes an unsorted slice of Dogus
Expand Down Expand Up @@ -64,48 +91,38 @@ func contains(slice []Dependency, item string) bool {
return false
}

func (bd *sortByDependency) Len() int {
return len(bd.dogus)
}

func (bd *sortByDependency) Swap(i, j int) {
bd.dogus[i], bd.dogus[j] = bd.dogus[j], bd.dogus[i]
func (bd *sortByDependency) sortDogusByDependency() ([]*Dogu, error) {
dependencyEdges := bd.getDependencyEdges()
sorted, err := toposort.Toposort(dependencyEdges)
return bd.handleSortResult(sorted, err)
}

func (bd *sortByDependency) Less(i, j int) bool {
leftName := bd.dogus[i].GetSimpleName()
rightName := bd.dogus[j].GetSimpleName()

leftDependenciesRecursive := bd.getAllDoguDependenciesRecursive(bd.dogus[i])
rightDependenciesRecursive := bd.getAllDoguDependenciesRecursive(bd.dogus[j])

leftDependenciesDirect := bd.dogus[i].GetAllDependenciesOfType(DependencyTypeDogu)
rightDependenciesDirect := bd.dogus[j].GetAllDependenciesOfType(DependencyTypeDogu)

if contains(rightDependenciesRecursive, leftName) {
return true
} else if contains(leftDependenciesRecursive, rightName) {
return false
} else if len(leftDependenciesDirect) == len(rightDependenciesDirect) {
return leftName < rightName
func (bd *sortByDependency) getDependencyEdges() []toposort.Edge {
var dependencyEdges []toposort.Edge
for _, dogu := range bd.dogus {
dependencies := dogu.GetAllDependenciesOfType(DependencyTypeDogu)
if len(dependencies) > 0 {
dependentDogus := bd.dependenciesToDogus(dependencies)
for _, dependency := range dependentDogus {
dependencyEdges = append(dependencyEdges, toposort.Edge{dependency, dogu})
}
} else {
dependencyEdges = append(dependencyEdges, toposort.Edge{nil, dogu})
}
}

return len(leftDependenciesDirect) < len(rightDependenciesDirect)
return dependencyEdges
}

func (bd *sortByDependency) getAllDoguDependenciesRecursive(inputDogu *Dogu) []Dependency {
dependencies := inputDogu.GetAllDependenciesOfType(DependencyTypeDogu)
dependenciesAsDogus := bd.dependenciesToDogus(dependencies)

for _, dogu := range dependenciesAsDogus {
for _, dep := range bd.getAllDoguDependenciesRecursive(dogu) {
if !contains(dependencies, dep.Name) {
dependencies = append(dependencies, dep)
}
func toDoguSlice(dogus []interface{}) ([]*Dogu, error) {
result := make([]*Dogu, len(dogus))
for i, dogu := range dogus {
if castedDogu, ok := dogu.(*Dogu); ok {
result[i] = castedDogu
} else {
return nil, fmt.Errorf("expected Dogu, got %T", dogu)
}
}

return dependencies
return result, nil
}

func (bd *sortByDependency) dependenciesToDogus(dependencies []Dependency) []*Dogu {
Expand All @@ -119,3 +136,26 @@ func (bd *sortByDependency) dependenciesToDogus(dependencies []Dependency) []*Do

return result
}

func (bd *sortByDependency) sortDogusByInvertedDependency() ([]*Dogu, error) {
dependencyEdges := bd.getDependencyEdges()
sorted, err := toposort.ToposortR(dependencyEdges)
return bd.handleSortResult(sorted, err)
}

func (bd *sortByDependency) handleSortResult(sorted []interface{}, err error) ([]*Dogu, error) {
if err != nil {
err = fmt.Errorf("sort by dependency failed: %s", err)
log.Error(err)
return nil, err
}

sortedDogus, err := toDoguSlice(sorted)
if err != nil {
err = fmt.Errorf("sort by dependency failed: %s", err)
log.Error(err)
return nil, err
}

return sortedDogus, nil
}
Loading

0 comments on commit df7982a

Please sign in to comment.