Skip to content

Commit 7960e44

Browse files
sywhangabhinav
andauthored
Refactor graph representation (uber-go#301)
This is the first PR to prepare Dig for in-graph modifications. This PR contains several changes to allow further extensibility in the graph representation used in Dig, and decouple reflection Type info from the graph algorithms as much as possible. Specifically, this PR makes the following changes: - Add `internal/graph` package which contains Dig-agnostic graph algorithm used for cycle detection - Remove the somewhat duplicated embedded cycle detection logic in Container and cycle.go - Add `graphHolder` type in `Container` which holds all the graph nodes and implements the graph iterator interface used for graph algorithm in `internal/graph`. - Add `paramGroupedSlice` as part of node in graph. - Remove the param visitor funcs and related helpers. - Rename `node` to `constructorNode`. There is also a change in the way cycle error messages are displayed. Previously, the errors looked like: ``` typeA provided by funcName (file_location.go:line_number) depends on typeB provided by funcName (file_location.go:line_number) depends on typeC provided by funcName (file_location.go:line_number) ... and so on ``` This error message generation depended on knowing the "edge" info between nodes, which is the reflect.Type that connects the two constructor nodes. Now that the graph representation holds not only constructor nodes but also value groups, and because graph representation does not know what type holds the nodes together, this needs to be changed. Now, the error messages look like: ``` func(*typeB) *typeA provided by funcName(file_location.go:line_number) depends on func(*typeC) *typeB provided by funcName(file_location.go:line_number) depends on func(*typeA) *typeC provided by funcName(file_location.go:line_number) ... and so on ``` (Note that the function signature is now printed instead of the type that holds the nodes as dependencies.) For param value groups, the error message skips over it so that the error message doesn't look cluttered but that can be subject to change in the future. Co-authored-by: Abhinav Gupta <[email protected]>
1 parent 173b7b1 commit 7960e44

File tree

13 files changed

+806
-480
lines changed

13 files changed

+806
-480
lines changed

cycle.go

Lines changed: 0 additions & 142 deletions
This file was deleted.

cycle_error.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright (c) 2019 Uber Technologies, Inc.
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a copy
4+
// of this software and associated documentation files (the "Software"), to deal
5+
// in the Software without restriction, including without limitation the rights
6+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
// copies of the Software, and to permit persons to whom the Software is
8+
// furnished to do so, subject to the following conditions:
9+
//
10+
// The above copyright notice and this permission notice shall be included in
11+
// all copies or substantial portions of the Software.
12+
//
13+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
// THE SOFTWARE.
20+
21+
package dig
22+
23+
import (
24+
"bytes"
25+
"fmt"
26+
27+
"go.uber.org/dig/internal/digreflect"
28+
)
29+
30+
type cycleErrPathEntry struct {
31+
Key key
32+
Func *digreflect.Func
33+
}
34+
35+
type errCycleDetected struct {
36+
Path []cycleErrPathEntry
37+
}
38+
39+
func (e errCycleDetected) Error() string {
40+
// We get something like,
41+
//
42+
// func(*bar) *foo provided by "path/to/package".NewFoo (path/to/file.go:42)
43+
// depends on func(*baz) *bar provided by "another/package".NewBar (somefile.go:1)
44+
// depends on func(*foo) baz provided by "somepackage".NewBar (anotherfile.go:2)
45+
// depends on func(*bar) *foo provided by "path/to/package".NewFoo (path/to/file.go:42)
46+
//
47+
b := new(bytes.Buffer)
48+
49+
for i, entry := range e.Path {
50+
if i > 0 {
51+
b.WriteString("\n\tdepends on ")
52+
}
53+
fmt.Fprintf(b, "%v provided by %v", entry.Key, entry.Func)
54+
}
55+
return b.String()
56+
}
57+
58+
// IsCycleDetected returns a boolean as to whether the provided error indicates
59+
// a cycle was detected in the container graph.
60+
func IsCycleDetected(err error) bool {
61+
_, ok := RootCause(err).(errCycleDetected)
62+
return ok
63+
}

0 commit comments

Comments
 (0)