internal/depgraph/module.go
package depgraph
import (
"fmt"
"time"
"github.com/Helcaraxan/gomod/internal/graph"
"github.com/Helcaraxan/gomod/internal/modules"
)
// Module represents a module in a Go module's dependency graph.
type Module struct {
Info *modules.ModuleInfo
Indirects map[string]bool
VersionConstraints map[string]VersionConstraint
predecessors graph.NodeRefs
successors graph.NodeRefs
packages graph.NodeRefs
isNonTestDependency bool
}
type VersionConstraint struct {
Source string
Target string
}
func NewModule(info *modules.ModuleInfo) *Module {
return &Module{
Info: info,
Indirects: map[string]bool{},
VersionConstraints: map[string]VersionConstraint{},
predecessors: graph.NewNodeRefs(),
successors: graph.NewNodeRefs(),
packages: graph.NewNodeRefs(),
}
}
// Name of the module represented by this Dependency in the Graph instance.
func (m *Module) Name() string {
return m.Info.Path
}
func (m *Module) Hash() string {
return moduleHash(m.Info.Path)
}
func (m *Module) String() string {
return fmt.Sprintf("%s, preds: [%s], succs: [%s]", m.Hash(), m.predecessors, m.successors)
}
func moduleHash(name string) string {
return "module " + name
}
// SelectedVersion corresponds to the version of the dependency represented by this Dependency which
// was selected for use.
func (m *Module) SelectedVersion() string {
if m.Info.Replace != nil {
return m.Info.Replace.Version
}
return m.Info.Version
}
// Timestamp returns the time corresponding to the creation of the version at which this dependency
// is used.
func (m *Module) Timestamp() *time.Time {
if m.Info.Replace != nil {
return m.Info.Replace.Time
}
return m.Info.Time
}
func (m *Module) Parent() graph.Node {
return nil
}
func (m *Module) Predecessors() *graph.NodeRefs {
return &m.predecessors
}
func (m *Module) Successors() *graph.NodeRefs {
return &m.successors
}
func (m *Module) Children() *graph.NodeRefs {
return &m.packages
}
func (m *Module) NodeAttributes(annotate bool) []string {
var annotations []string
text, background := hashToColourHSV(m.Hash(), m.isTestDependency())
annotations = append(annotations, fmt.Sprintf(`fontcolor="%s"`, text), fmt.Sprintf(`fillcolor="%s"`, background))
if annotate && m.SelectedVersion() != "" {
var replacement string
if m.Info.Replace != nil {
replacement = m.Info.Replace.Path + "<br />"
}
annotations = append(
annotations,
fmt.Sprintf("label=<%s<br /><font point-size=\"10\">%s%s</font>>", m.Name(), replacement, m.SelectedVersion()),
)
}
return annotations
}
func (m *Module) EdgeAttributes(target graph.Node, annotate bool) []string {
targetModule := target.(*Module)
var annotations []string
if m.Indirects[target.Name()] {
annotations = append(annotations, "style=dashed") //nolint:misspell
}
if target.(testAnnotated).isTestDependency() {
annotations = append(annotations, "color=lightblue") //nolint:misspell
}
if c, ok := m.VersionConstraints[targetModule.Hash()]; ok && annotate {
annotations = append(annotations, fmt.Sprintf("label=<<font point-size=\"10\">%s</font>>", c.Target))
}
return annotations
}
var _ testAnnotated = &Module{}
func (m *Module) isTestDependency() bool {
return !m.isNonTestDependency
}