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