Source file src/cmd/go/internal/modcmd/graph.go

     1  // Copyright 2018 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // go mod graph
     6  
     7  package modcmd
     8  
     9  import (
    10  	"bufio"
    11  	"context"
    12  	"os"
    13  
    14  	"cmd/go/internal/base"
    15  	"cmd/go/internal/cfg"
    16  	"cmd/go/internal/gover"
    17  	"cmd/go/internal/modload"
    18  	"cmd/go/internal/toolchain"
    19  
    20  	"golang.org/x/mod/module"
    21  )
    22  
    23  var cmdGraph = &base.Command{
    24  	UsageLine: "go mod graph [-go=version] [-x]",
    25  	Short:     "print module requirement graph",
    26  	Long: `
    27  Graph prints the module requirement graph (with replacements applied)
    28  in text form. Each line in the output has two space-separated fields: a module
    29  and one of its requirements. Each module is identified as a string of the form
    30  path@version, except for the main module, which has no @version suffix.
    31  
    32  The -go flag causes graph to report the module graph as loaded by the
    33  given Go version, instead of the version indicated by the 'go' directive
    34  in the go.mod file.
    35  
    36  The -x flag causes graph to print the commands graph executes.
    37  
    38  See https://golang.org/ref/mod#go-mod-graph for more about 'go mod graph'.
    39  	`,
    40  	Run: runGraph,
    41  }
    42  
    43  var (
    44  	graphGo goVersionFlag
    45  )
    46  
    47  func init() {
    48  	cmdGraph.Flag.Var(&graphGo, "go", "")
    49  	cmdGraph.Flag.BoolVar(&cfg.BuildX, "x", false, "")
    50  	base.AddChdirFlag(&cmdGraph.Flag)
    51  	base.AddModCommonFlags(&cmdGraph.Flag)
    52  }
    53  
    54  func runGraph(ctx context.Context, cmd *base.Command, args []string) {
    55  	modload.InitWorkfile()
    56  
    57  	if len(args) > 0 {
    58  		base.Fatalf("go: 'go mod graph' accepts no arguments")
    59  	}
    60  	modload.ForceUseModules = true
    61  	modload.RootMode = modload.NeedRoot
    62  
    63  	goVersion := graphGo.String()
    64  	if goVersion != "" && gover.Compare(gover.Local(), goVersion) < 0 {
    65  		toolchain.SwitchOrFatal(ctx, &gover.TooNewError{
    66  			What:      "-go flag",
    67  			GoVersion: goVersion,
    68  		})
    69  	}
    70  
    71  	mg, err := modload.LoadModGraph(ctx, goVersion)
    72  	if err != nil {
    73  		base.Fatal(err)
    74  	}
    75  
    76  	w := bufio.NewWriter(os.Stdout)
    77  	defer w.Flush()
    78  
    79  	format := func(m module.Version) {
    80  		w.WriteString(m.Path)
    81  		if m.Version != "" {
    82  			w.WriteString("@")
    83  			w.WriteString(m.Version)
    84  		}
    85  	}
    86  
    87  	mg.WalkBreadthFirst(func(m module.Version) {
    88  		reqs, _ := mg.RequiredBy(m)
    89  		for _, r := range reqs {
    90  			format(m)
    91  			w.WriteByte(' ')
    92  			format(r)
    93  			w.WriteByte('\n')
    94  		}
    95  	})
    96  }
    97  

View as plain text