...

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

View as plain text