blob: 172c1dda5ce8fbbe30105ce49944e4b06ce4a78f [file] [log] [blame]
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// go mod graph
package modcmd
import (
"bufio"
"context"
"os"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/gover"
"cmd/go/internal/modload"
"cmd/go/internal/toolchain"
"golang.org/x/mod/module"
)
var cmdGraph = &base.Command{
UsageLine: "go mod graph [-go=version] [-x]",
Short: "print module requirement graph",
Long: `
Graph prints the module requirement graph (with replacements applied)
in text form. Each line in the output has two space-separated fields: a module
and one of its requirements. Each module is identified as a string of the form
path@version, except for the main module, which has no @version suffix.
The -go flag causes graph to report the module graph as loaded by the
given Go version, instead of the version indicated by the 'go' directive
in the go.mod file.
The -x flag causes graph to print the commands graph executes.
See https://golang.org/ref/mod#go-mod-graph for more about 'go mod graph'.
`,
Run: runGraph,
}
var (
graphGo goVersionFlag
)
func init() {
cmdGraph.Flag.Var(&graphGo, "go", "")
cmdGraph.Flag.BoolVar(&cfg.BuildX, "x", false, "")
base.AddChdirFlag(&cmdGraph.Flag)
base.AddModCommonFlags(&cmdGraph.Flag)
}
func runGraph(ctx context.Context, cmd *base.Command, args []string) {
modload.InitWorkfile()
if len(args) > 0 {
base.Fatalf("go: 'go mod graph' accepts no arguments")
}
modload.ForceUseModules = true
modload.RootMode = modload.NeedRoot
goVersion := graphGo.String()
if goVersion != "" && gover.Compare(gover.Local(), goVersion) < 0 {
toolchain.SwitchOrFatal(ctx, &gover.TooNewError{
What: "-go flag",
GoVersion: goVersion,
})
}
mg, err := modload.LoadModGraph(ctx, goVersion)
if err != nil {
base.Fatal(err)
}
w := bufio.NewWriter(os.Stdout)
defer w.Flush()
format := func(m module.Version) {
w.WriteString(m.Path)
if m.Version != "" {
w.WriteString("@")
w.WriteString(m.Version)
}
}
mg.WalkBreadthFirst(func(m module.Version) {
reqs, _ := mg.RequiredBy(m)
for _, r := range reqs {
format(m)
w.WriteByte(' ')
format(r)
w.WriteByte('\n')
}
})
}