Skip to content

Commit b95d571

Browse files
authored
Merge pull request kubernetes#87226 from liggitt/simplify-code-generator
Simplify code generator dependencies
2 parents 93595eb + e8a8bdb commit b95d571

File tree

31 files changed

+130
-1702
lines changed

31 files changed

+130
-1702
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ require (
127127
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4
128128
golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72
129129
gonum.org/v1/gonum v0.6.2
130+
gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e // indirect
130131
google.golang.org/api v0.6.1-0.20190607001116-5213b8090861
131132
google.golang.org/grpc v1.23.1
132133
gopkg.in/gcfg.v1 v1.2.0

staging/src/k8s.io/apiextensions-apiserver/go.sum

Lines changed: 0 additions & 29 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

staging/src/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/BUILD

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,6 @@ go_library(
2323
"//staging/src/k8s.io/code-generator/pkg/util:go_default_library",
2424
"//staging/src/k8s.io/code-generator/third_party/forked/golang/reflect:go_default_library",
2525
"//vendor/github.com/spf13/pflag:go_default_library",
26-
"//vendor/gonum.org/v1/gonum/graph:go_default_library",
27-
"//vendor/gonum.org/v1/gonum/graph/simple:go_default_library",
28-
"//vendor/gonum.org/v1/gonum/graph/topo:go_default_library",
2926
"//vendor/k8s.io/gengo/args:go_default_library",
3027
"//vendor/k8s.io/gengo/generator:go_default_library",
3128
"//vendor/k8s.io/gengo/namer:go_default_library",
@@ -37,7 +34,10 @@ go_library(
3734

3835
go_test(
3936
name = "go_default_test",
40-
srcs = ["namer_test.go"],
37+
srcs = [
38+
"cmd_test.go",
39+
"namer_test.go",
40+
],
4141
embed = [":go_default_library"],
4242
)
4343

staging/src/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/cmd.go

Lines changed: 60 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,6 @@ import (
2929
"strings"
3030

3131
flag "github.com/spf13/pflag"
32-
"gonum.org/v1/gonum/graph"
33-
"gonum.org/v1/gonum/graph/simple"
34-
"gonum.org/v1/gonum/graph/topo"
3532

3633
"k8s.io/code-generator/pkg/util"
3734
"k8s.io/gengo/args"
@@ -374,38 +371,73 @@ func deps(c *generator.Context, pkgs []*protobufPackage) map[string][]string {
374371
return ret
375372
}
376373

374+
// given a set of pkg->[]deps, return the order that ensures all deps are processed before the things that depend on them
377375
func importOrder(deps map[string][]string) ([]string, error) {
378-
nodes := map[string]graph.Node{}
379-
names := map[int64]string{}
380-
g := simple.NewDirectedGraph()
381-
for pkg, imports := range deps {
382-
for _, imp := range imports {
383-
if _, found := nodes[pkg]; !found {
384-
n := g.NewNode()
385-
g.AddNode(n)
386-
nodes[pkg] = n
387-
names[n.ID()] = pkg
388-
}
389-
if _, found := nodes[imp]; !found {
390-
n := g.NewNode()
391-
g.AddNode(n)
392-
nodes[imp] = n
393-
names[n.ID()] = imp
394-
}
395-
g.SetEdge(g.NewEdge(nodes[imp], nodes[pkg]))
376+
// add all nodes and edges
377+
var remainingNodes = map[string]struct{}{}
378+
var graph = map[edge]struct{}{}
379+
for to, froms := range deps {
380+
remainingNodes[to] = struct{}{}
381+
for _, from := range froms {
382+
remainingNodes[from] = struct{}{}
383+
graph[edge{from: from, to: to}] = struct{}{}
396384
}
397385
}
398386

399-
ret := []string{}
400-
sorted, err := topo.Sort(g)
401-
if err != nil {
402-
return nil, err
387+
// find initial nodes without any dependencies
388+
sorted := findAndRemoveNodesWithoutDependencies(remainingNodes, graph)
389+
for i := 0; i < len(sorted); i++ {
390+
node := sorted[i]
391+
removeEdgesFrom(node, graph)
392+
sorted = append(sorted, findAndRemoveNodesWithoutDependencies(remainingNodes, graph)...)
393+
}
394+
if len(remainingNodes) > 0 {
395+
return nil, fmt.Errorf("cycle: remaining nodes: %#v, remaining edges: %#v", remainingNodes, graph)
403396
}
404397
for _, n := range sorted {
405-
ret = append(ret, names[n.ID()])
406-
fmt.Println("topological order", names[n.ID()])
398+
fmt.Println("topological order", n)
399+
}
400+
return sorted, nil
401+
}
402+
403+
// edge describes a from->to relationship in a graph
404+
type edge struct {
405+
from string
406+
to string
407+
}
408+
409+
// findAndRemoveNodesWithoutDependencies finds nodes in the given set which are not pointed to by any edges in the graph,
410+
// removes them from the set of nodes, and returns them in sorted order
411+
func findAndRemoveNodesWithoutDependencies(nodes map[string]struct{}, graph map[edge]struct{}) []string {
412+
roots := []string{}
413+
// iterate over all nodes as potential "to" nodes
414+
for node := range nodes {
415+
incoming := false
416+
// iterate over all remaining edges
417+
for edge := range graph {
418+
// if there's any edge to the node we care about, it's not a root
419+
if edge.to == node {
420+
incoming = true
421+
break
422+
}
423+
}
424+
// if there are no incoming edges, remove from the set of remaining nodes and add to our results
425+
if !incoming {
426+
delete(nodes, node)
427+
roots = append(roots, node)
428+
}
429+
}
430+
sort.Strings(roots)
431+
return roots
432+
}
433+
434+
// removeEdgesFrom removes any edges from the graph where edge.from == node
435+
func removeEdgesFrom(node string, graph map[edge]struct{}) {
436+
for edge := range graph {
437+
if edge.from == node {
438+
delete(graph, edge)
439+
}
407440
}
408-
return ret, nil
409441
}
410442

411443
type positionOrder struct {
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
Copyright 2020 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package protobuf
18+
19+
import (
20+
"reflect"
21+
"testing"
22+
)
23+
24+
func TestImportOrder(t *testing.T) {
25+
testcases := []struct {
26+
Name string
27+
Input map[string][]string
28+
Expect []string
29+
ExpectErr bool
30+
}{
31+
{
32+
Name: "empty",
33+
Input: nil,
34+
Expect: []string{},
35+
},
36+
{
37+
Name: "simple",
38+
Input: map[string][]string{"apps": {"core", "extensions", "meta"}, "extensions": {"core", "meta"}, "core": {"meta"}},
39+
Expect: []string{"meta", "core", "extensions", "apps"},
40+
},
41+
{
42+
Name: "cycle",
43+
Input: map[string][]string{"apps": {"core", "extensions", "meta"}, "extensions": {"core", "meta"}, "core": {"meta", "apps"}},
44+
ExpectErr: true,
45+
},
46+
}
47+
48+
for _, tc := range testcases {
49+
t.Run(tc.Name, func(t *testing.T) {
50+
order, err := importOrder(tc.Input)
51+
if err != nil {
52+
if !tc.ExpectErr {
53+
t.Fatalf("unexpected error: %v", err)
54+
}
55+
return
56+
}
57+
if tc.ExpectErr {
58+
t.Fatalf("expected error, got none")
59+
}
60+
if !reflect.DeepEqual(order, tc.Expect) {
61+
t.Fatalf("expected %v, got %v", tc.Expect, order)
62+
}
63+
})
64+
}
65+
}

staging/src/k8s.io/code-generator/go.mod

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ require (
1616
github.com/stretchr/testify v1.4.0 // indirect
1717
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 // indirect
1818
golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72 // indirect
19-
gonum.org/v1/gonum v0.6.2
20-
gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e // indirect
2119
gopkg.in/yaml.v2 v2.2.7 // indirect
2220
k8s.io/gengo v0.0.0-20190822140433-26a664648505
2321
k8s.io/klog v1.0.0

0 commit comments

Comments
 (0)