Skip to content

Commit 7d3cf25

Browse files
committed
initial semantic refactoring
1 parent 6f87b9b commit 7d3cf25

File tree

3 files changed

+74
-35
lines changed

3 files changed

+74
-35
lines changed

alpha/declcfg/write.go

Lines changed: 50 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"io"
88
"os"
99
"path/filepath"
10+
"slices"
1011
"sort"
1112
"strings"
1213

@@ -33,6 +34,7 @@ func NewMermaidWriter(opts ...MermaidOption) *MermaidWriter {
3334
m := &MermaidWriter{
3435
MinEdgeName: minEdgeName,
3536
SpecifiedPackageName: specifiedPackageName,
37+
UseV0Semantics: true,
3638
}
3739

3840
for _, opt := range opts {
@@ -53,9 +55,9 @@ func WithSpecifiedPackageName(specifiedPackageName string) MermaidOption {
5355
}
5456
}
5557

56-
func WithV0Semantics() MermaidOption {
58+
func WithV0Semantics(useV0Semantics bool) MermaidOption {
5759
return func(o *MermaidWriter) {
58-
o.UseV0Semantics = true
60+
o.UseV0Semantics = useV0Semantics
5961
}
6062
}
6163

@@ -131,7 +133,8 @@ func (writer *MermaidWriter) WriteChannels(cfg DeclarativeConfig, out io.Writer)
131133
}
132134

133135
var deprecatedPackage string
134-
deprecatedChannels := []string{}
136+
deprecatedChannelIDs := []string{}
137+
decoratedBundleIDs := map[string][]string{"deprecated": {}, "skipped": {}, "deprecatedskipped": {}}
135138
linkID := 0
136139
skippedLinkIDs := []string{}
137140

@@ -154,7 +157,7 @@ func (writer *MermaidWriter) WriteChannels(cfg DeclarativeConfig, out io.Writer)
154157
}
155158

156159
if depByChannel.Has(filteredChannel.Name) {
157-
deprecatedChannels = append(deprecatedChannels, channelID)
160+
deprecatedChannelIDs = append(deprecatedChannelIDs, channelID)
158161
}
159162

160163
// sort edges by decreasing version
@@ -169,29 +172,45 @@ func (writer *MermaidWriter) WriteChannels(cfg DeclarativeConfig, out io.Writer)
169172

170173
skippedEntities := sets.Set[string]{}
171174

175+
const (
176+
captureNewEntry = true
177+
processExisting = false
178+
)
179+
handleSemantics := func(edge string, linkID int, captureNew bool) {
180+
if writer.UseV0Semantics {
181+
if captureNew {
182+
if skippedEntities.Has(edge) {
183+
skippedLinkIDs = append(skippedLinkIDs, fmt.Sprintf("%d", linkID))
184+
} else {
185+
skippedEntities.Insert(edge)
186+
}
187+
} else {
188+
if skippedEntities.Has(edge) {
189+
skippedLinkIDs = append(skippedLinkIDs, fmt.Sprintf("%d", linkID))
190+
}
191+
}
192+
}
193+
}
194+
172195
for _, ce := range sortedEntries {
173-
bundleDecoration := ""
196+
entryID := fmt.Sprintf("%s-%s", channelID, ce.Name)
197+
fmt.Fprintf(pkgBuilder, " %s[%q]\n", entryID, ce.Name)
198+
199+
// mermaid allows specification of only a single decoration class, so any combinations must be independently represented
174200
switch {
175201
case depByBundle.Has(ce.Name) && skippedEntities.Has(ce.Name):
176-
bundleDecoration = ":::depandskip"
202+
decoratedBundleIDs["deprecatedskipped"] = append(decoratedBundleIDs["deprecatedskipped"], entryID)
177203
case depByBundle.Has(ce.Name):
178-
bundleDecoration = ":::deprecated"
204+
decoratedBundleIDs["deprecated"] = append(decoratedBundleIDs["deprecated"], entryID)
179205
case skippedEntities.Has(ce.Name):
180-
bundleDecoration = ":::skipped"
206+
decoratedBundleIDs["skipped"] = append(decoratedBundleIDs["skipped"], entryID)
181207
}
182208

183-
entryID := fmt.Sprintf("%s-%s", channelID, ce.Name)
184-
fmt.Fprintf(pkgBuilder, " %s[%q]%s\n", entryID, ce.Name, bundleDecoration)
185-
186209
if len(ce.Skips) > 0 {
187210
for _, s := range ce.Skips {
188211
skipsID := fmt.Sprintf("%s-%s", channelID, s)
189212
fmt.Fprintf(pkgBuilder, " %s[%q]-- %s --> %s[%q]\n", skipsID, s, "skip", entryID, ce.Name)
190-
if skippedEntities.Has(s) {
191-
skippedLinkIDs = append(skippedLinkIDs, fmt.Sprintf("%d", linkID))
192-
} else {
193-
skippedEntities.Insert(s)
194-
}
213+
handleSemantics(s, linkID, captureNewEntry)
195214
linkID++
196215
}
197216
}
@@ -202,9 +221,7 @@ func (writer *MermaidWriter) WriteChannels(cfg DeclarativeConfig, out io.Writer)
202221
if skipRange(versionMap[edgeName.Name]) {
203222
skipRangeID := fmt.Sprintf("%s-%s", channelID, edgeName.Name)
204223
fmt.Fprintf(pkgBuilder, " %s[%q]-- \"%s(%s)\" --> %s[%q]\n", skipRangeID, edgeName.Name, "skipRange", ce.SkipRange, entryID, ce.Name)
205-
if skippedEntities.Has(ce.Name) {
206-
skippedLinkIDs = append(skippedLinkIDs, fmt.Sprintf("%d", linkID))
207-
}
224+
handleSemantics(ce.Name, linkID, processExisting)
208225
linkID++
209226
}
210227
}
@@ -216,9 +233,7 @@ func (writer *MermaidWriter) WriteChannels(cfg DeclarativeConfig, out io.Writer)
216233
if len(ce.Replaces) > 0 {
217234
replacesID := fmt.Sprintf("%s-%s", channelID, ce.Replaces)
218235
fmt.Fprintf(pkgBuilder, " %s[%q]-- %s --> %s[%q]\n", replacesID, ce.Replaces, "replace", entryID, ce.Name)
219-
if skippedEntities.Has(ce.Name) {
220-
skippedLinkIDs = append(skippedLinkIDs, fmt.Sprintf("%d", linkID))
221-
}
236+
handleSemantics(ce.Name, linkID, processExisting)
222237
linkID++
223238
}
224239
}
@@ -229,7 +244,7 @@ func (writer *MermaidWriter) WriteChannels(cfg DeclarativeConfig, out io.Writer)
229244
_, _ = out.Write([]byte("graph LR\n"))
230245
_, _ = out.Write([]byte(" classDef deprecated fill:#E8960F\n"))
231246
_, _ = out.Write([]byte(" classDef skipped stroke:#FF0000,stroke-width:4px\n"))
232-
_, _ = out.Write([]byte(" classDef depandskip fill:#E8960,stroke:#FF0000,stroke-width:4px\n"))
247+
_, _ = out.Write([]byte(" classDef deprecatedskipped fill:#E8960F,stroke:#FF0000,stroke-width:4px\n"))
233248
pkgNames := []string{}
234249
for pname := range pkgs {
235250
pkgNames = append(pkgNames, pname)
@@ -248,14 +263,23 @@ func (writer *MermaidWriter) WriteChannels(cfg DeclarativeConfig, out io.Writer)
248263
_, _ = out.Write([]byte(fmt.Sprintf("style %s fill:#989695\n", deprecatedPackage)))
249264
}
250265

251-
if len(deprecatedChannels) > 0 {
252-
for _, deprecatedChannel := range deprecatedChannels {
266+
if len(deprecatedChannelIDs) > 0 {
267+
for _, deprecatedChannel := range deprecatedChannelIDs {
253268
_, _ = out.Write([]byte(fmt.Sprintf("style %s fill:#DCD0FF\n", deprecatedChannel)))
254269
}
255270
}
256271

272+
// express the decoration classes
273+
for key := range decoratedBundleIDs {
274+
if len(decoratedBundleIDs[key]) > 0 {
275+
b := slices.Clone(decoratedBundleIDs[key])
276+
slices.Sort(b)
277+
_, _ = out.Write([]byte(fmt.Sprintf("class %s %s\n", strings.Join(b, ","), key)))
278+
}
279+
}
280+
257281
if len(skippedLinkIDs) > 0 {
258-
_, _ = out.Write([]byte("linkStyle " + strings.Join(skippedLinkIDs, ",") + " stroke:#FF0000,stroke-width:3px,stroke-dasharray:5;"))
282+
_, _ = out.Write([]byte("linkStyle " + strings.Join(skippedLinkIDs, ",") + " stroke:#FF0000,stroke-width:3px,stroke-dasharray:5;\n"))
259283
}
260284

261285
return nil

alpha/declcfg/write_test.go

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -527,35 +527,40 @@ func TestWriteMermaidChannels(t *testing.T) {
527527
packageFilter: "",
528528
expected: `graph LR
529529
classDef deprecated fill:#E8960F
530+
classDef skipped stroke:#FF0000,stroke-width:4px
531+
classDef deprecatedskipped fill:#E8960F,stroke:#FF0000,stroke-width:4px
530532
%% package "anakin"
531533
subgraph "anakin"
532534
%% channel "dark"
533535
subgraph anakin-dark["dark"]
534-
anakin-dark-anakin.v0.0.1["anakin.v0.0.1"]:::deprecated
535-
anakin-dark-anakin.v0.1.0["anakin.v0.1.0"]
536-
anakin-dark-anakin.v0.0.1["anakin.v0.0.1"]-- replace --> anakin-dark-anakin.v0.1.0["anakin.v0.1.0"]
537536
anakin-dark-anakin.v0.1.1["anakin.v0.1.1"]
538-
anakin-dark-anakin.v0.0.1["anakin.v0.0.1"]-- replace --> anakin-dark-anakin.v0.1.1["anakin.v0.1.1"]
539537
anakin-dark-anakin.v0.1.0["anakin.v0.1.0"]-- skip --> anakin-dark-anakin.v0.1.1["anakin.v0.1.1"]
538+
anakin-dark-anakin.v0.0.1["anakin.v0.0.1"]-- replace --> anakin-dark-anakin.v0.1.1["anakin.v0.1.1"]
539+
anakin-dark-anakin.v0.1.0["anakin.v0.1.0"]
540+
anakin-dark-anakin.v0.0.1["anakin.v0.0.1"]-- replace --> anakin-dark-anakin.v0.1.0["anakin.v0.1.0"]
541+
anakin-dark-anakin.v0.0.1["anakin.v0.0.1"]
540542
end
541543
%% channel "light"
542544
subgraph anakin-light["light"]
543-
anakin-light-anakin.v0.0.1["anakin.v0.0.1"]:::deprecated
544545
anakin-light-anakin.v0.1.0["anakin.v0.1.0"]
545546
anakin-light-anakin.v0.0.1["anakin.v0.0.1"]-- replace --> anakin-light-anakin.v0.1.0["anakin.v0.1.0"]
547+
anakin-light-anakin.v0.0.1["anakin.v0.0.1"]
546548
end
547549
end
548550
%% package "boba-fett"
549551
subgraph "boba-fett"
550552
%% channel "mando"
551553
subgraph boba-fett-mando["mando"]
552-
boba-fett-mando-boba-fett.v1.0.0["boba-fett.v1.0.0"]
553554
boba-fett-mando-boba-fett.v2.0.0["boba-fett.v2.0.0"]
554555
boba-fett-mando-boba-fett.v1.0.0["boba-fett.v1.0.0"]-- replace --> boba-fett-mando-boba-fett.v2.0.0["boba-fett.v2.0.0"]
556+
boba-fett-mando-boba-fett.v1.0.0["boba-fett.v1.0.0"]
555557
end
556558
end
557559
style anakin fill:#989695
558560
style anakin-light fill:#DCD0FF
561+
class anakin-dark-anakin.v0.0.1,anakin-light-anakin.v0.0.1 deprecated
562+
class anakin-dark-anakin.v0.1.0 skipped
563+
linkStyle 2 stroke:#FF0000,stroke-width:3px,stroke-dasharray:5;
559564
`,
560565
},
561566
{
@@ -565,13 +570,15 @@ style anakin-light fill:#DCD0FF
565570
packageFilter: "",
566571
expected: `graph LR
567572
classDef deprecated fill:#E8960F
573+
classDef skipped stroke:#FF0000,stroke-width:4px
574+
classDef deprecatedskipped fill:#E8960F,stroke:#FF0000,stroke-width:4px
568575
%% package "anakin"
569576
subgraph "anakin"
570577
%% channel "dark"
571578
subgraph anakin-dark["dark"]
572-
anakin-dark-anakin.v0.1.0["anakin.v0.1.0"]
573579
anakin-dark-anakin.v0.1.1["anakin.v0.1.1"]
574580
anakin-dark-anakin.v0.1.0["anakin.v0.1.0"]-- skip --> anakin-dark-anakin.v0.1.1["anakin.v0.1.1"]
581+
anakin-dark-anakin.v0.1.0["anakin.v0.1.0"]
575582
end
576583
%% channel "light"
577584
subgraph anakin-light["light"]
@@ -580,6 +587,7 @@ style anakin-light fill:#DCD0FF
580587
end
581588
style anakin fill:#989695
582589
style anakin-light fill:#DCD0FF
590+
class anakin-dark-anakin.v0.1.0 skipped
583591
`,
584592
},
585593
{
@@ -589,13 +597,15 @@ style anakin-light fill:#DCD0FF
589597
packageFilter: "boba-fett",
590598
expected: `graph LR
591599
classDef deprecated fill:#E8960F
600+
classDef skipped stroke:#FF0000,stroke-width:4px
601+
classDef deprecatedskipped fill:#E8960F,stroke:#FF0000,stroke-width:4px
592602
%% package "boba-fett"
593603
subgraph "boba-fett"
594604
%% channel "mando"
595605
subgraph boba-fett-mando["mando"]
596-
boba-fett-mando-boba-fett.v1.0.0["boba-fett.v1.0.0"]
597606
boba-fett-mando-boba-fett.v2.0.0["boba-fett.v2.0.0"]
598607
boba-fett-mando-boba-fett.v1.0.0["boba-fett.v1.0.0"]-- replace --> boba-fett-mando-boba-fett.v2.0.0["boba-fett.v2.0.0"]
608+
boba-fett-mando-boba-fett.v1.0.0["boba-fett.v1.0.0"]
599609
end
600610
end
601611
`,

cmd/opm/alpha/render-graph/cmd.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ func NewCmd() *cobra.Command {
1818
render action.Render
1919
minEdge string
2020
specifiedPackageName string
21+
includeV0Semantics bool
2122
)
2223
cmd := &cobra.Command{
2324
Use: "render-graph [index-image | fbc-dir]",
@@ -67,13 +68,17 @@ $ opm alpha render-graph quay.io/operatorhubio/catalog:latest | \
6768
log.Fatal(err)
6869
}
6970

70-
writer := declcfg.NewMermaidWriter(declcfg.WithMinEdgeName(minEdge), declcfg.WithSpecifiedPackageName(specifiedPackageName))
71+
writer := declcfg.NewMermaidWriter(
72+
declcfg.WithMinEdgeName(minEdge),
73+
declcfg.WithSpecifiedPackageName(specifiedPackageName),
74+
declcfg.WithV0Semantics(includeV0Semantics))
7175
if err := writer.WriteChannels(*cfg, os.Stdout); err != nil {
7276
log.Fatal(err)
7377
}
7478
},
7579
}
7680
cmd.Flags().StringVar(&minEdge, "minimum-edge", "", "the channel edge to be used as the lower bound of the set of edges composing the upgrade graph; default is to include all edges")
7781
cmd.Flags().StringVarP(&specifiedPackageName, "package-name", "p", "", "a specific package name to filter output; default is to include all packages in reference")
82+
cmd.Flags().BoolVar(&includeV0Semantics, "include-v0-semantics", false, "whether to indicate OLMv0 semantics in the output; default is to simply represent the upgrade graph")
7883
return cmd
7984
}

0 commit comments

Comments
 (0)