]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/go: enter vendor mode depending on new modules.txt workspace line
authorMichael Matloob <matloob@golang.org>
Wed, 26 Jul 2023 18:09:06 +0000 (14:09 -0400)
committerMichael Matloob <matloob@golang.org>
Fri, 11 Aug 2023 01:59:23 +0000 (01:59 +0000)
modules.txt gets a new ## workspace line at the start of the file if
it's generated in workspace mode. Then, when deciding whether the go
command runs in mod=vendor, we only do so if we're in the same mode
(workspace or not) as the modules.txt specifies.

For #60056

Change-Id: If478a9891a7135614326fcb80c4c33a431e4e531
Reviewed-on: https://go-review.googlesource.com/c/go/+/513756
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Bryan Mills <bcmills@google.com>
Run-TryBot: Bryan Mills <bcmills@google.com>

src/cmd/go/internal/modcmd/vendor.go
src/cmd/go/internal/modload/init.go
src/cmd/go/testdata/script/work_vendor_modules_txt_conditional.txt [new file with mode: 0644]
src/cmd/go/testdata/script/work_vendor_modules_txt_consistent.txt
src/cmd/go/testdata/script/work_vendor_prune.txt
src/cmd/go/testdata/script/work_vendor_prune_all.txt

index 82a267587a15ee0b603a2f7a5ae70b963ec6a5fc..033d47b10468193a4e3795679004033de0573dd2 100644 (file)
@@ -155,6 +155,10 @@ func RunVendor(ctx context.Context, vendorE bool, vendorO string, args []string)
                w = io.MultiWriter(&buf, os.Stderr)
        }
 
+       if modload.MainModules.WorkFile() != nil {
+               fmt.Fprintf(w, "## workspace\n")
+       }
+
        replacementWritten := make(map[module.Version]bool)
        for _, m := range vendorMods {
                replacement := modload.Replacement(m)
index 5ab46d5693ead02997a0304e8da5899902d71ded..8629dff2016570957ce64cbb7ff8553cb1bbe802 100644 (file)
@@ -11,6 +11,7 @@ import (
        "errors"
        "fmt"
        "internal/lazyregexp"
+       "io"
        "os"
        "path"
        "path/filepath"
@@ -1408,26 +1409,69 @@ func setDefaultBuildMod() {
                if fi, err := fsys.Stat(vendorDir); err == nil && fi.IsDir() {
                        modGo := "unspecified"
                        if goVersion != "" {
-                               if gover.Compare(goVersion, "1.14") >= 0 {
-                                       // The Go version is at least 1.14, and a vendor directory exists.
-                                       // Set -mod=vendor by default.
-                                       cfg.BuildMod = "vendor"
-                                       cfg.BuildModReason = "Go version in " + versionSource + " is at least 1.14 and vendor directory exists."
-                                       return
+                               if gover.Compare(goVersion, "1.14") < 0 {
+                                       // The go version is less than 1.14. Don't set -mod=vendor by default.
+                                       // Since a vendor directory exists, we should record why we didn't use it.
+                                       // This message won't normally be shown, but it may appear with import errors.
+                                       cfg.BuildModReason = fmt.Sprintf("Go version in "+versionSource+" is %s, so vendor directory was not used.", modGo)
                                } else {
-                                       modGo = goVersion
+                                       vendoredWorkspace, err := modulesTextIsForWorkspace(vendorDir)
+                                       if err != nil {
+                                               base.Fatalf("go: reading modules.txt for vendor directory: %v", err)
+                                       }
+                                       if vendoredWorkspace != (versionSource == "go.work") {
+                                               if vendoredWorkspace {
+                                                       cfg.BuildModReason = "Outside workspace mode, but vendor directory is for a workspace."
+                                               } else {
+                                                       cfg.BuildModReason = "In workspace mode, but vendor directory is not for a workspace"
+                                               }
+                                       } else {
+                                               // The Go version is at least 1.14, a vendor directory exists, and
+                                               // the modules.txt was generated in the same mode the command is running in.
+                                               // Set -mod=vendor by default.
+                                               cfg.BuildMod = "vendor"
+                                               cfg.BuildModReason = "Go version in " + versionSource + " is at least 1.14 and vendor directory exists."
+                                               return
+                                       }
                                }
+                               modGo = goVersion
                        }
 
-                       // Since a vendor directory exists, we should record why we didn't use it.
-                       // This message won't normally be shown, but it may appear with import errors.
-                       cfg.BuildModReason = fmt.Sprintf("Go version in "+versionSource+" is %s, so vendor directory was not used.", modGo)
                }
        }
 
        cfg.BuildMod = "readonly"
 }
 
+func modulesTextIsForWorkspace(vendorDir string) (bool, error) {
+       f, err := fsys.Open(filepath.Join(vendorDir, "modules.txt"))
+       if errors.Is(err, os.ErrNotExist) {
+               // Some vendor directories exist that don't contain modules.txt.
+               // This mostly happens when converting to modules.
+               // We want to preserve the behavior that mod=vendor is set (even though
+               // readVendorList does nothing in that case).
+               return false, nil
+       }
+       if err != nil {
+               return false, err
+       }
+       var buf [512]byte
+       n, err := f.Read(buf[:])
+       if err != nil && err != io.EOF {
+               return false, err
+       }
+       line, _, _ := strings.Cut(string(buf[:n]), "\n")
+       if annotations, ok := strings.CutPrefix(line, "## "); ok {
+               for _, entry := range strings.Split(annotations, ";") {
+                       entry = strings.TrimSpace(entry)
+                       if entry == "workspace" {
+                               return true, nil
+                       }
+               }
+       }
+       return false, nil
+}
+
 func mustHaveCompleteRequirements() bool {
        return cfg.BuildMod != "mod" && !inWorkspaceMode()
 }
diff --git a/src/cmd/go/testdata/script/work_vendor_modules_txt_conditional.txt b/src/cmd/go/testdata/script/work_vendor_modules_txt_conditional.txt
new file mode 100644 (file)
index 0000000..3d671eb
--- /dev/null
@@ -0,0 +1,62 @@
+# This test checks to see if we only start in workspace vendor
+# mode if the modules.txt specifies ## workspace (and only in
+# standard vendor if it doesn't).
+
+# vendor directory produced for workspace, workspace mode
+# runs in mod=vendor
+go work vendor
+cmp vendor/modules.txt want_workspace_modules_txt
+go list -f {{.Dir}} example.com/b
+stdout $GOPATH[\\/]src[\\/]vendor[\\/]example.com[\\/]b
+
+# vendor directory produced for workspace, module mode
+# runs in mod=readonly
+env GOWORK=off
+go list -f {{.Dir}} example.com/b
+stdout $GOPATH[\\/]src[\\/]b
+
+# vendor directory produced for module, module mode
+# runs in mod=vendor
+go mod vendor
+cmp vendor/modules.txt want_module_modules_txt
+go list -f {{.Dir}} example.com/b
+stdout $GOPATH[\\/]src[\\/]vendor[\\/]example.com[\\/]b
+
+# vendor directory produced for module, workspace mode
+# runs in mod=readonly
+env GOWORK=
+go list -f {{.Dir}} example.com/b
+stdout $GOPATH[\\/]src[\\/]b
+
+-- want_workspace_modules_txt --
+## workspace
+# example.com/b v0.0.0 => ./b
+## explicit; go 1.21
+example.com/b
+# example.com/b => ./b
+-- want_module_modules_txt --
+# example.com/b v0.0.0 => ./b
+## explicit; go 1.21
+example.com/b
+# example.com/b => ./b
+-- go.work --
+go 1.21
+
+use .
+-- go.mod --
+module example.com/a
+
+go 1.21
+
+require example.com/b v0.0.0
+replace example.com/b => ./b
+-- a.go --
+package a
+
+import _ "example.com/b"
+-- b/go.mod --
+module example.com/b
+
+go 1.21
+-- b/b.go --
+package b
\ No newline at end of file
index 038e1a54d665b2a1e666c6cb3fc6826f53db7a61..bc0f068fd04bf48afc98804a90974e1d99d3c53d 100644 (file)
@@ -28,11 +28,13 @@ cp modules.txt.extra_replacement vendor/modules.txt
 cmpenv stderr extra_replacement_error.txt
 
 -- modules.txt.want --
+## workspace
 # example.com/p v1.0.0 => ./p
 ## explicit; go 1.21
 # example.com/q v1.0.0 => ./q
 ## explicit; go 1.21
 -- modules.txt.required_but_not_explicit --
+## workspace
 # example.com/p v1.0.0 => ./p
 ## go 1.21
 # example.com/q v1.0.0 => ./q
@@ -45,6 +47,7 @@ go: inconsistent vendoring in $GOPATH${/}src:
        To sync the vendor directory, run:
                go work vendor
 -- modules.txt.missing_replacement --
+## workspace
 # example.com/p v1.0.0
 ## explicit; go 1.21
 # example.com/q v1.0.0 => ./q
@@ -57,6 +60,7 @@ go: inconsistent vendoring in $GOPATH${/}src:
        To sync the vendor directory, run:
                go work vendor
 -- modules.txt.different_replacement --
+## workspace
 # example.com/p v1.0.0 => ./r
 ## explicit; go 1.21
 # example.com/q v1.0.0 => ./q
@@ -69,6 +73,7 @@ go: inconsistent vendoring in $GOPATH${/}src:
        To sync the vendor directory, run:
                go work vendor
 -- modules.txt.extra_explicit --
+## workspace
 # example.com/p v1.0.0 => ./p
 ## explicit; go 1.21
 # example.com/q v1.0.0 => ./q
@@ -84,6 +89,7 @@ go: inconsistent vendoring in $GOPATH${/}src:
        To sync the vendor directory, run:
                go work vendor
 -- modules.txt.extra_replacement --
+## workspace
 # example.com/p v1.0.0 => ./p
 ## explicit; go 1.21
 # example.com/q v1.0.0 => ./q
index 5972cc70d68e4b5319566da7578cff9cf1db3817..424b4d59da0bb317bb3528e8d0f77b90b771f7ae 100644 (file)
@@ -22,6 +22,7 @@ go run example.com/p
 stdout 'version 1.1.0'
 
 -- modules.txt.want --
+## workspace
 # example.com/b v1.0.0 => ./b
 ## explicit; go 1.18
 example.com/b
index b004afddf72338fb52065170d232df9785ef9cda..a369d22bd808cb03158add21e8f4d938a5eddd78 100644 (file)
@@ -18,6 +18,7 @@ stdout $GOPATH[\\/]src[\\/]vendor[\\/]example.com[\\/]z
 cmp $GOPATH/src/vendor/example.com/q/q.go q1_1_0/q.go
 
 -- modules.txt.want --
+## workspace
 # example.com/b v1.0.0 => ./b
 ## explicit; go 1.18
 example.com/b