-
Notifications
You must be signed in to change notification settings - Fork 187
/
state.go
140 lines (118 loc) · 4.78 KB
/
state.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/*
* Copyright (c) Microsoft Corporation.
* Licensed under the MIT license.
*/
package pipeline
import (
"github.com/pkg/errors"
kerrors "k8s.io/apimachinery/pkg/util/errors"
"github.com/Azure/azure-service-operator/v2/internal/set"
"github.com/Azure/azure-service-operator/v2/tools/generator/internal/astmodel"
"github.com/Azure/azure-service-operator/v2/tools/generator/internal/codegen/storage"
)
// State is an immutable instance that captures the information being passed along the pipeline
type State struct {
definitions astmodel.TypeDefinitionSet // set of type definitions generated so far
conversionGraph *storage.ConversionGraph // graph of transitions between packages in our conversion graph
exportedConfigMaps *ExportedTypeNameProperties
stagesSeen set.Set[string] // set of ids of the stages already run
stagesExpected map[string]set.Set[string] // set of ids of expected stages, each with a set of ids for the stages expecting them
}
/*
* TODO: Future extension (suggested by @matthchr):
* Instead of hard coding specific knowledge in the state type, implement a generic solution where stages can stash
* information in a map indexed by their unique identifier; later stages can then retrieve that information using
* that identifier.
*/
// NewState returns a new empty state
// definitions is a (possibly empty) sequence of types to combine for the initial state
func NewState(definitions ...astmodel.TypeDefinitionSet) *State {
defs := make(astmodel.TypeDefinitionSet)
for _, ts := range definitions {
defs = defs.OverlayWith(ts)
}
return &State{
definitions: defs,
conversionGraph: nil,
stagesSeen: set.Make[string](),
stagesExpected: make(map[string]set.Set[string]),
}
}
// WithDefinitions returns a new independentState with the given type definitions instead
func (s *State) WithDefinitions(definitions astmodel.TypeDefinitionSet) *State {
result := s.copy()
result.definitions = definitions
return result
}
// WithOverlaidDefinitions returns a new independent State with the given type definitions overlaid on the existing ones.
// Any new definitions are added, and any existing definitions are replaced.
func (s *State) WithOverlaidDefinitions(definitions astmodel.TypeDefinitionSet) *State {
result := s.copy()
result.definitions = result.definitions.OverlayWith(definitions)
return result
}
// WithConversionGraph returns a new independent State with the given conversion graph instead
func (s *State) WithConversionGraph(graph *storage.ConversionGraph) *State {
result := s.copy()
result.conversionGraph = graph
return result
}
// WithGeneratedConfigMaps returns a new independent State with the given generated config maps
func (s *State) WithGeneratedConfigMaps(exportedConfigMaps *ExportedTypeNameProperties) *State {
if s.exportedConfigMaps != nil {
panic("may only set the generated config mappings once")
}
result := s.copy()
result.exportedConfigMaps = exportedConfigMaps
return result
}
// WithSeenStage records that the passed stage has been seen
func (s *State) WithSeenStage(id string) *State {
result := s.copy()
result.stagesSeen.Add(id) // Record that we saw this stage
delete(result.stagesExpected, id) // Discard expectations as they are satisfied
return result
}
// WithExpectation records our expectation that the later stage is coming
func (s *State) WithExpectation(earlierStage string, laterStage string) *State {
result := s.copy()
if set, ok := result.stagesExpected[laterStage]; ok {
set.Add(earlierStage)
return result
}
set := set.Make(earlierStage)
result.stagesExpected[laterStage] = set
return result
}
// Definitions returns the set of type definitions contained by the state
func (s *State) Definitions() astmodel.TypeDefinitionSet {
return s.definitions
}
// ConversionGraph returns the conversion graph included in our state (may be null)
func (s *State) ConversionGraph() *storage.ConversionGraph {
return s.conversionGraph
}
// GeneratedConfigMaps returns the set of generated config maps
func (s *State) GeneratedConfigMaps() *ExportedTypeNameProperties {
return s.exportedConfigMaps
}
// CheckFinalState checks that our final state is valid, returning an error if not
func (s *State) CheckFinalState() error {
var errs []error
for required, requiredBy := range s.stagesExpected {
for stageId := range requiredBy {
errs = append(errs, errors.Errorf("postrequisite %q of stage %q not satisfied", required, stageId))
}
}
return kerrors.NewAggregate(errs)
}
// copy creates a new independent copy of the state
func (s *State) copy() *State {
return &State{
definitions: s.definitions.Copy(),
conversionGraph: s.conversionGraph,
exportedConfigMaps: s.exportedConfigMaps.Copy(),
stagesSeen: s.stagesSeen,
stagesExpected: s.stagesExpected,
}
}