github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/go/not-internal/modcmd/why.go (about)

     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  package modcmd
     6  
     7  import (
     8  	"fmt"
     9  	"strings"
    10  
    11  	"github.com/gagliardetto/golang-go/cmd/go/not-internal/base"
    12  	"github.com/gagliardetto/golang-go/cmd/go/not-internal/modload"
    13  	"github.com/gagliardetto/golang-go/cmd/go/not-internal/work"
    14  
    15  	"golang.org/x/mod/module"
    16  )
    17  
    18  var cmdWhy = &base.Command{
    19  	UsageLine: "go mod why [-m] [-vendor] packages...",
    20  	Short:     "explain why packages or modules are needed",
    21  	Long: `
    22  Why shows a shortest path in the import graph from the main module to
    23  each of the listed packages. If the -m flag is given, why treats the
    24  arguments as a list of modules and finds a path to any package in each
    25  of the modules.
    26  
    27  By default, why queries the graph of packages matched by "go list all",
    28  which includes tests for reachable packages. The -vendor flag causes why
    29  to exclude tests of dependencies.
    30  
    31  The output is a sequence of stanzas, one for each package or module
    32  name on the command line, separated by blank lines. Each stanza begins
    33  with a comment line "# package" or "# module" giving the target
    34  package or module. Subsequent lines give a path through the import
    35  graph, one package per line. If the package or module is not
    36  referenced from the main module, the stanza will display a single
    37  parenthesized note indicating that fact.
    38  
    39  For example:
    40  
    41  	$ go mod why golang.org/x/text/language golang.org/x/text/encoding
    42  	# golang.org/x/text/language
    43  	rsc.io/quote
    44  	rsc.io/sampler
    45  	golang.org/x/text/language
    46  
    47  	# golang.org/x/text/encoding
    48  	(main module does not need package golang.org/x/text/encoding)
    49  	$
    50  	`,
    51  }
    52  
    53  var (
    54  	whyM      = cmdWhy.Flag.Bool("m", false, "")
    55  	whyVendor = cmdWhy.Flag.Bool("vendor", false, "")
    56  )
    57  
    58  func init() {
    59  	cmdWhy.Run = runWhy // break init cycle
    60  	work.AddModCommonFlags(cmdWhy)
    61  }
    62  
    63  func runWhy(cmd *base.Command, args []string) {
    64  	loadALL := modload.LoadALL
    65  	if *whyVendor {
    66  		loadALL = modload.LoadVendor
    67  	}
    68  	if *whyM {
    69  		listU := false
    70  		listVersions := false
    71  		for _, arg := range args {
    72  			if strings.Contains(arg, "@") {
    73  				base.Fatalf("go mod why: module query not allowed")
    74  			}
    75  		}
    76  		mods := modload.ListModules(args, listU, listVersions)
    77  		byModule := make(map[module.Version][]string)
    78  		for _, path := range loadALL() {
    79  			m := modload.PackageModule(path)
    80  			if m.Path != "" {
    81  				byModule[m] = append(byModule[m], path)
    82  			}
    83  		}
    84  		sep := ""
    85  		for _, m := range mods {
    86  			best := ""
    87  			bestDepth := 1000000000
    88  			for _, path := range byModule[module.Version{Path: m.Path, Version: m.Version}] {
    89  				d := modload.WhyDepth(path)
    90  				if d > 0 && d < bestDepth {
    91  					best = path
    92  					bestDepth = d
    93  				}
    94  			}
    95  			why := modload.Why(best)
    96  			if why == "" {
    97  				vendoring := ""
    98  				if *whyVendor {
    99  					vendoring = " to vendor"
   100  				}
   101  				why = "(main module does not need" + vendoring + " module " + m.Path + ")\n"
   102  			}
   103  			fmt.Printf("%s# %s\n%s", sep, m.Path, why)
   104  			sep = "\n"
   105  		}
   106  	} else {
   107  		matches := modload.ImportPaths(args) // resolve to packages
   108  		loadALL()                            // rebuild graph, from main module (not from named packages)
   109  		sep := ""
   110  		for _, m := range matches {
   111  			for _, path := range m.Pkgs {
   112  				why := modload.Why(path)
   113  				if why == "" {
   114  					vendoring := ""
   115  					if *whyVendor {
   116  						vendoring = " to vendor"
   117  					}
   118  					why = "(main module does not need" + vendoring + " package " + path + ")\n"
   119  				}
   120  				fmt.Printf("%s# %s\n%s", sep, path, why)
   121  				sep = "\n"
   122  			}
   123  		}
   124  	}
   125  }