1
1
package core
2
2
3
3
import (
4
+ "fmt"
5
+ "github.com/gammazero/toposort"
4
6
"sort"
5
7
)
6
8
7
9
// SortDogusByDependency takes an unsorted slice of Dogu structs and returns a slice of Dogus ordered by the
8
10
// 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
9
15
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 ) {
10
23
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
13
30
}
14
31
15
32
// SortDogusByInvertedDependency takes an unsorted slice of Dogu structs and returns a new slice of Dogus ordered by the
16
33
// 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
17
38
func SortDogusByInvertedDependency (dogus []* Dogu ) []* Dogu {
18
- orderedDesc := SortDogusByDependency (dogus )
39
+ orderedDogus , _ := SortDogusByInvertedDependencyWithError (dogus )
40
+ return orderedDogus
41
+ }
19
42
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 )
23
51
}
24
-
25
- return orderedAsc
52
+ return orderedDogus , err
26
53
}
27
54
28
55
// SortDogusByName takes an unsorted slice of Dogus
@@ -64,48 +91,38 @@ func contains(slice []Dependency, item string) bool {
64
91
return false
65
92
}
66
93
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 )
73
98
}
74
99
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
+ }
91
112
}
92
-
93
- return len (leftDependenciesDirect ) < len (rightDependenciesDirect )
113
+ return dependencyEdges
94
114
}
95
115
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 )
105
123
}
106
124
}
107
-
108
- return dependencies
125
+ return result , nil
109
126
}
110
127
111
128
func (bd * sortByDependency ) dependenciesToDogus (dependencies []Dependency ) []* Dogu {
@@ -119,3 +136,26 @@ func (bd *sortByDependency) dependenciesToDogus(dependencies []Dependency) []*Do
119
136
120
137
return result
121
138
}
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