71 lines
1.4 KiB
Go
71 lines
1.4 KiB
Go
|
package depgraph
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"fmt"
|
||
|
"sort"
|
||
|
)
|
||
|
|
||
|
// Graph is used to represent a dependency graph.
|
||
|
type Graph struct {
|
||
|
Nodes []Node
|
||
|
}
|
||
|
|
||
|
// Node is an element of the graph that has other dependencies.
|
||
|
type Node interface {
|
||
|
Deps() []Node
|
||
|
}
|
||
|
|
||
|
// NamedNode is an optional interface implementation of a Node that
|
||
|
// can have a name. If this is implemented, this will be used for various
|
||
|
// output.
|
||
|
type NamedNode interface {
|
||
|
Node
|
||
|
Name() string
|
||
|
}
|
||
|
|
||
|
func (g *Graph) String() string {
|
||
|
var buf bytes.Buffer
|
||
|
|
||
|
// Build the list of node names and a mapping so that we can more
|
||
|
// easily alphabetize the output to remain deterministic.
|
||
|
names := make([]string, 0, len(g.Nodes))
|
||
|
mapping := make(map[string]Node, len(g.Nodes))
|
||
|
for _, n := range g.Nodes {
|
||
|
name := nodeName(n)
|
||
|
names = append(names, name)
|
||
|
mapping[name] = n
|
||
|
}
|
||
|
sort.Strings(names)
|
||
|
|
||
|
// Write each node in order...
|
||
|
for _, name := range names {
|
||
|
n := mapping[name]
|
||
|
buf.WriteString(fmt.Sprintf("%s\n", name))
|
||
|
|
||
|
// Alphabetize dependencies
|
||
|
depsRaw := n.Deps()
|
||
|
deps := make([]string, 0, len(depsRaw))
|
||
|
for _, d := range depsRaw {
|
||
|
deps = append(deps, nodeName(d))
|
||
|
}
|
||
|
sort.Strings(deps)
|
||
|
|
||
|
// Write dependencies
|
||
|
for _, d := range deps {
|
||
|
buf.WriteString(fmt.Sprintf(" %s\n", d))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return buf.String()
|
||
|
}
|
||
|
|
||
|
func nodeName(n Node) string {
|
||
|
switch v := n.(type) {
|
||
|
case NamedNode:
|
||
|
return v.Name()
|
||
|
default:
|
||
|
return fmt.Sprintf("%s", v)
|
||
|
}
|
||
|
}
|