github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/go/modcmd/tidy.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  // go mod tidy
     6  
     7  package modcmd
     8  
     9  import (
    10  	"context"
    11  	"fmt"
    12  
    13  	"github.com/go-asm/go/cmd/go/base"
    14  	"github.com/go-asm/go/cmd/go/cfg"
    15  	"github.com/go-asm/go/cmd/go/gover"
    16  	"github.com/go-asm/go/cmd/go/imports"
    17  	"github.com/go-asm/go/cmd/go/modload"
    18  	"github.com/go-asm/go/cmd/go/toolchain"
    19  
    20  	"golang.org/x/mod/modfile"
    21  )
    22  
    23  var cmdTidy = &base.Command{
    24  	UsageLine: "go mod tidy [-e] [-v] [-x] [-go=version] [-compat=version]",
    25  	Short:     "add missing and remove unused modules",
    26  	Long: `
    27  Tidy makes sure go.mod matches the source code in the module.
    28  It adds any missing modules necessary to build the current module's
    29  packages and dependencies, and it removes unused modules that
    30  don't provide any relevant packages. It also adds any missing entries
    31  to go.sum and removes any unnecessary ones.
    32  
    33  The -v flag causes tidy to print information about removed modules
    34  to standard error.
    35  
    36  The -e flag causes tidy to attempt to proceed despite errors
    37  encountered while loading packages.
    38  
    39  The -go flag causes tidy to update the 'go' directive in the go.mod
    40  file to the given version, which may change which module dependencies
    41  are retained as explicit requirements in the go.mod file.
    42  (Go versions 1.17 and higher retain more requirements in order to
    43  support lazy module loading.)
    44  
    45  The -compat flag preserves any additional checksums needed for the
    46  'go' command from the indicated major Go release to successfully load
    47  the module graph, and causes tidy to error out if that version of the
    48  'go' command would load any imported package from a different module
    49  version. By default, tidy acts as if the -compat flag were set to the
    50  version prior to the one indicated by the 'go' directive in the go.mod
    51  file.
    52  
    53  The -x flag causes tidy to print the commands download executes.
    54  
    55  See https://golang.org/ref/mod#go-mod-tidy for more about 'go mod tidy'.
    56  	`,
    57  	Run: runTidy,
    58  }
    59  
    60  var (
    61  	tidyE      bool          // if true, report errors but proceed anyway.
    62  	tidyGo     goVersionFlag // go version to write to the tidied go.mod file (toggles lazy loading)
    63  	tidyCompat goVersionFlag // go version for which the tidied go.mod and go.sum files should be “compatible”
    64  )
    65  
    66  func init() {
    67  	cmdTidy.Flag.BoolVar(&cfg.BuildV, "v", false, "")
    68  	cmdTidy.Flag.BoolVar(&cfg.BuildX, "x", false, "")
    69  	cmdTidy.Flag.BoolVar(&tidyE, "e", false, "")
    70  	cmdTidy.Flag.Var(&tidyGo, "go", "")
    71  	cmdTidy.Flag.Var(&tidyCompat, "compat", "")
    72  	base.AddChdirFlag(&cmdTidy.Flag)
    73  	base.AddModCommonFlags(&cmdTidy.Flag)
    74  }
    75  
    76  // A goVersionFlag is a flag.Value representing a supported Go version.
    77  //
    78  // (Note that the -go argument to 'go mod edit' is *not* a goVersionFlag.
    79  // It intentionally allows newer-than-supported versions as arguments.)
    80  type goVersionFlag struct {
    81  	v string
    82  }
    83  
    84  func (f *goVersionFlag) String() string { return f.v }
    85  func (f *goVersionFlag) Get() any       { return f.v }
    86  
    87  func (f *goVersionFlag) Set(s string) error {
    88  	if s != "" {
    89  		latest := gover.Local()
    90  		if !modfile.GoVersionRE.MatchString(s) {
    91  			return fmt.Errorf("expecting a Go version like %q", latest)
    92  		}
    93  		if gover.Compare(s, latest) > 0 {
    94  			return fmt.Errorf("maximum supported Go version is %s", latest)
    95  		}
    96  	}
    97  
    98  	f.v = s
    99  	return nil
   100  }
   101  
   102  func runTidy(ctx context.Context, cmd *base.Command, args []string) {
   103  	if len(args) > 0 {
   104  		base.Fatalf("go: 'go mod tidy' accepts no arguments")
   105  	}
   106  
   107  	// Tidy aims to make 'go test' reproducible for any package in 'all', so we
   108  	// need to include test dependencies. For modules that specify go 1.15 or
   109  	// earlier this is a no-op (because 'all' saturates transitive test
   110  	// dependencies).
   111  	//
   112  	// However, with lazy loading (go 1.16+) 'all' includes only the packages that
   113  	// are transitively imported by the main module, not the test dependencies of
   114  	// those packages. In order to make 'go test' reproducible for the packages
   115  	// that are in 'all' but outside of the main module, we must explicitly
   116  	// request that their test dependencies be included.
   117  	modload.ForceUseModules = true
   118  	modload.RootMode = modload.NeedRoot
   119  
   120  	goVersion := tidyGo.String()
   121  	if goVersion != "" && gover.Compare(gover.Local(), goVersion) < 0 {
   122  		toolchain.SwitchOrFatal(ctx, &gover.TooNewError{
   123  			What:      "-go flag",
   124  			GoVersion: goVersion,
   125  		})
   126  	}
   127  
   128  	modload.LoadPackages(ctx, modload.PackageOpts{
   129  		TidyGoVersion:            tidyGo.String(),
   130  		Tags:                     imports.AnyTags(),
   131  		Tidy:                     true,
   132  		TidyCompatibleVersion:    tidyCompat.String(),
   133  		VendorModulesInGOROOTSrc: true,
   134  		ResolveMissingImports:    true,
   135  		LoadTests:                true,
   136  		AllowErrors:              tidyE,
   137  		SilenceMissingStdImports: true,
   138  		Switcher:                 new(toolchain.Switcher),
   139  	}, "all")
   140  }