Skip to content

Commit df7982a

Browse files
nhinze23cesmarvin
authored andcommitted
Merge branch 'release/v0.14.1' into main
2 parents 607453e + ef9bd19 commit df7982a

File tree

7 files changed

+925
-210
lines changed

7 files changed

+925
-210
lines changed

CHANGELOG.md

+8
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

88
## [Unreleased]
99

10+
## [v0.14.1] - 2024-10-17
11+
### Changed
12+
- use topological sorting to sort dogus by dependency
13+
14+
### Deprecated
15+
- `SortDogusByDependency`: Use `SortDogusByDependencyWithError` instead for better error handling
16+
- `SortDogusByInvertedDependency`: Use `SortDogusByInvertedDependencyWithError` instead for better error handling
17+
1018
## [v0.14.0] - 2024-09-18
1119
### Changed
1220
- Relicense to AGPL-3.0-only (#40)

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Set these to the desired values
22
ARTIFACT_ID=cesapp-lib
3-
VERSION=0.14.0
3+
VERSION=0.14.1
44

55
GOTAG?=1.18.6
66
MAKEFILES_VERSION=7.4.0

core/dogu-sort.go

+83-43
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,55 @@
11
package core
22

33
import (
4+
"fmt"
5+
"github.com/gammazero/toposort"
46
"sort"
57
)
68

79
// SortDogusByDependency takes an unsorted slice of Dogu structs and returns a slice of Dogus ordered by the
810
// importance of their dependencies descending, that is: the most needed dogu will be the first element.
11+
//
12+
// Deprecated: This function returns nil on error. For better error-handling use SortDogusByDependencyWithError instead.
13+
//
14+
//goland:noinspection GoDeprecation
915
func SortDogusByDependency(dogus []*Dogu) []*Dogu {
16+
orderedDogus, _ := SortDogusByDependencyWithError(dogus)
17+
return orderedDogus
18+
}
19+
20+
// SortDogusByDependencyWithError takes an unsorted slice of Dogu structs and returns a slice of Dogus ordered by the
21+
// importance of their dependencies descending, that is: the most needed dogu will be the first element.
22+
func SortDogusByDependencyWithError(dogus []*Dogu) ([]*Dogu, error) {
1023
ordered := sortByDependency{dogus}
11-
sort.Stable(&ordered)
12-
return ordered.dogus
24+
orderedDogus, err := ordered.sortDogusByDependency()
25+
if err != nil {
26+
err = fmt.Errorf("error in sorting dogus by dependency: %s", err)
27+
log.Error(err)
28+
}
29+
return orderedDogus, err
1330
}
1431

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

20-
orderedAsc := []*Dogu{}
21-
for i := len(orderedDesc) - 1; i >= 0; i-- {
22-
orderedAsc = append(orderedAsc, dogus[i])
43+
// SortDogusByInvertedDependencyWithError takes an unsorted slice of Dogu structs and returns a new slice of Dogus ordered by the
44+
// importance of their dependencies ascending, that is: the most independent dogu will be the first element.
45+
func SortDogusByInvertedDependencyWithError(dogus []*Dogu) ([]*Dogu, error) {
46+
ordered := sortByDependency{dogus}
47+
orderedDogus, err := ordered.sortDogusByInvertedDependency()
48+
if err != nil {
49+
err = fmt.Errorf("error in sorting dogus by inverted dependency: %s", err)
50+
log.Error(err)
2351
}
24-
25-
return orderedAsc
52+
return orderedDogus, err
2653
}
2754

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

67-
func (bd *sortByDependency) Len() int {
68-
return len(bd.dogus)
69-
}
70-
71-
func (bd *sortByDependency) Swap(i, j int) {
72-
bd.dogus[i], bd.dogus[j] = bd.dogus[j], bd.dogus[i]
94+
func (bd *sortByDependency) sortDogusByDependency() ([]*Dogu, error) {
95+
dependencyEdges := bd.getDependencyEdges()
96+
sorted, err := toposort.Toposort(dependencyEdges)
97+
return bd.handleSortResult(sorted, err)
7398
}
7499

75-
func (bd *sortByDependency) Less(i, j int) bool {
76-
leftName := bd.dogus[i].GetSimpleName()
77-
rightName := bd.dogus[j].GetSimpleName()
78-
79-
leftDependenciesRecursive := bd.getAllDoguDependenciesRecursive(bd.dogus[i])
80-
rightDependenciesRecursive := bd.getAllDoguDependenciesRecursive(bd.dogus[j])
81-
82-
leftDependenciesDirect := bd.dogus[i].GetAllDependenciesOfType(DependencyTypeDogu)
83-
rightDependenciesDirect := bd.dogus[j].GetAllDependenciesOfType(DependencyTypeDogu)
84-
85-
if contains(rightDependenciesRecursive, leftName) {
86-
return true
87-
} else if contains(leftDependenciesRecursive, rightName) {
88-
return false
89-
} else if len(leftDependenciesDirect) == len(rightDependenciesDirect) {
90-
return leftName < rightName
100+
func (bd *sortByDependency) getDependencyEdges() []toposort.Edge {
101+
var dependencyEdges []toposort.Edge
102+
for _, dogu := range bd.dogus {
103+
dependencies := dogu.GetAllDependenciesOfType(DependencyTypeDogu)
104+
if len(dependencies) > 0 {
105+
dependentDogus := bd.dependenciesToDogus(dependencies)
106+
for _, dependency := range dependentDogus {
107+
dependencyEdges = append(dependencyEdges, toposort.Edge{dependency, dogu})
108+
}
109+
} else {
110+
dependencyEdges = append(dependencyEdges, toposort.Edge{nil, dogu})
111+
}
91112
}
92-
93-
return len(leftDependenciesDirect) < len(rightDependenciesDirect)
113+
return dependencyEdges
94114
}
95115

96-
func (bd *sortByDependency) getAllDoguDependenciesRecursive(inputDogu *Dogu) []Dependency {
97-
dependencies := inputDogu.GetAllDependenciesOfType(DependencyTypeDogu)
98-
dependenciesAsDogus := bd.dependenciesToDogus(dependencies)
99-
100-
for _, dogu := range dependenciesAsDogus {
101-
for _, dep := range bd.getAllDoguDependenciesRecursive(dogu) {
102-
if !contains(dependencies, dep.Name) {
103-
dependencies = append(dependencies, dep)
104-
}
116+
func toDoguSlice(dogus []interface{}) ([]*Dogu, error) {
117+
result := make([]*Dogu, len(dogus))
118+
for i, dogu := range dogus {
119+
if castedDogu, ok := dogu.(*Dogu); ok {
120+
result[i] = castedDogu
121+
} else {
122+
return nil, fmt.Errorf("expected Dogu, got %T", dogu)
105123
}
106124
}
107-
108-
return dependencies
125+
return result, nil
109126
}
110127

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

120137
return result
121138
}
139+
140+
func (bd *sortByDependency) sortDogusByInvertedDependency() ([]*Dogu, error) {
141+
dependencyEdges := bd.getDependencyEdges()
142+
sorted, err := toposort.ToposortR(dependencyEdges)
143+
return bd.handleSortResult(sorted, err)
144+
}
145+
146+
func (bd *sortByDependency) handleSortResult(sorted []interface{}, err error) ([]*Dogu, error) {
147+
if err != nil {
148+
err = fmt.Errorf("sort by dependency failed: %s", err)
149+
log.Error(err)
150+
return nil, err
151+
}
152+
153+
sortedDogus, err := toDoguSlice(sorted)
154+
if err != nil {
155+
err = fmt.Errorf("sort by dependency failed: %s", err)
156+
log.Error(err)
157+
return nil, err
158+
}
159+
160+
return sortedDogus, nil
161+
}

0 commit comments

Comments
 (0)