]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/go: improve the creation and editing of go.work files
authorMichael Matloob <matloob@golang.org>
Fri, 3 Sep 2021 17:33:37 +0000 (13:33 -0400)
committerMichael Matloob <matloob@golang.org>
Wed, 8 Sep 2021 18:47:32 +0000 (18:47 +0000)
This change changes go.work files so that directory paths are clearly
distinguished from module paths by either being rooted absolute paths or
starting with '.' or '..' path elements if they are relative paths.
go mod initwork now checks that the go.work file doesn't already exist
before creating it, and gomod initwork and gomod editwork look up the
module path corresponding to a directory and write it to the directory
directive's comment.

For #45713

Change-Id: I6983779059b7de6fc83d359280ceffb263f6b641
Reviewed-on: https://go-review.googlesource.com/c/go/+/347591
Trust: Michael Matloob <matloob@golang.org>
Run-TryBot: Michael Matloob <matloob@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Jay Conrod <jayconrod@google.com>
src/cmd/go/internal/modcmd/editwork.go
src/cmd/go/internal/modload/init.go
src/cmd/go/internal/modload/modfile.go
src/cmd/go/testdata/script/work.txt
src/cmd/go/testdata/script/work_edit.txt

index f05d9245e7da3eb875d7e52659a9ceda8a2ce7e7..29895b1620cc8fa183badb59a5cc80c18a4a7d8a 100644 (file)
@@ -15,6 +15,7 @@ import (
        "encoding/json"
        "errors"
        "os"
+       "path/filepath"
        "strings"
 
        "golang.org/x/mod/modfile"
@@ -191,7 +192,13 @@ func runEditwork(ctx context.Context, cmd *base.Command, args []string) {
 // flagEditworkDirectory implements the -directory flag.
 func flagEditworkDirectory(arg string) {
        workedits = append(workedits, func(f *modfile.WorkFile) {
-               if err := f.AddDirectory(arg, ""); err != nil {
+               _, mf, err := modload.ReadModFile(filepath.Join(arg, "go.mod"), nil)
+               modulePath := ""
+               if err == nil {
+                       modulePath = mf.Module.Mod.Path
+               }
+               f.AddDirectory(modload.ToDirectoryPath(arg), modulePath)
+               if err := f.AddDirectory(modload.ToDirectoryPath(arg), ""); err != nil {
                        base.Fatalf("go mod: -directory=%s: %v", arg, err)
                }
        })
@@ -200,7 +207,7 @@ func flagEditworkDirectory(arg string) {
 // flagEditworkDropDirectory implements the -dropdirectory flag.
 func flagEditworkDropDirectory(arg string) {
        workedits = append(workedits, func(f *modfile.WorkFile) {
-               if err := f.DropDirectory(arg); err != nil {
+               if err := f.DropDirectory(modload.ToDirectoryPath(arg)); err != nil {
                        base.Fatalf("go mod: -dropdirectory=%s: %v", arg, err)
                }
        })
index bc155c7310f2b33d5427659fdfa9f47041845233..a1016ec5a328d583749ef94819d2f2840ce09b38 100644 (file)
@@ -634,29 +634,10 @@ func loadModFile(ctx context.Context) (rs *Requirements, needCommit bool) {
        var indices []*modFileIndex
        for _, modroot := range modRoots {
                gomod := modFilePath(modroot)
-               var data []byte
-               var err error
-               if gomodActual, ok := fsys.OverlayPath(gomod); ok {
-                       // Don't lock go.mod if it's part of the overlay.
-                       // On Plan 9, locking requires chmod, and we don't want to modify any file
-                       // in the overlay. See #44700.
-                       data, err = os.ReadFile(gomodActual)
-               } else {
-                       data, err = lockedfile.Read(gomodActual)
-               }
-               if err != nil {
-                       base.Fatalf("go: %v", err)
-               }
-
                var fixed bool
-               f, err := modfile.Parse(gomod, data, fixVersion(ctx, &fixed))
+               data, f, err := ReadModFile(gomod, fixVersion(ctx, &fixed))
                if err != nil {
-                       // Errors returned by modfile.Parse begin with file:line.
-                       base.Fatalf("go: errors parsing go.mod:\n%s\n", err)
-               }
-               if f.Module == nil {
-                       // No module declaration. Must add module path.
-                       base.Fatalf("go: no module declaration in go.mod. To specify the module path:\n\tgo mod edit -module=example.com/mod")
+                       base.Fatalf("go: %v", err)
                }
 
                modFiles = append(modFiles, f)
@@ -819,7 +800,9 @@ func CreateModFile(ctx context.Context, modPath string) {
 
 // CreateWorkFile initializes a new workspace by creating a go.work file.
 func CreateWorkFile(ctx context.Context, workFile string, modDirs []string) {
-       _ = TODOWorkspaces("Report an error if the file already exists.")
+       if _, err := fsys.Stat(workFile); err == nil {
+               base.Fatalf("go: %s already exists", workFile)
+       }
 
        goV := LatestGoVersion() // Use current Go version by default
        workF := new(modfile.WorkFile)
@@ -827,12 +810,18 @@ func CreateWorkFile(ctx context.Context, workFile string, modDirs []string) {
        workF.AddGoStmt(goV)
 
        for _, dir := range modDirs {
-               _ = TODOWorkspaces("Add the module path of the module.")
-               workF.AddDirectory(dir, "")
+               _, f, err := ReadModFile(filepath.Join(dir, "go.mod"), nil)
+               if err != nil {
+                       if os.IsNotExist(err) {
+                               base.Fatalf("go: creating workspace file: no go.mod file exists in directory %v", dir)
+                       }
+                       base.Fatalf("go: error parsing go.mod in directory %s: %v", dir, err)
+               }
+               workF.AddDirectory(ToDirectoryPath(dir), f.Module.Mod.Path)
        }
 
        data := modfile.Format(workF.Syntax)
-       lockedfile.Write(workFile, bytes.NewReader(data), 0644)
+       lockedfile.Write(workFile, bytes.NewReader(data), 0666)
 }
 
 // fixVersion returns a modfile.VersionFixer implemented using the Query function.
index 79ac1227caf4856fc29ffd9f07b8b3879ffa5796..bf05e92ba2e18903dd2068ed962b5ad4b4f5dd08 100644 (file)
@@ -47,6 +47,34 @@ const (
        separateIndirectVersionV = "v1.17"
 )
 
+// ReadModFile reads and parses the mod file at gomod. ReadModFile properly applies the
+// overlay, locks the file while reading, and applies fix, if applicable.
+func ReadModFile(gomod string, fix modfile.VersionFixer) (data []byte, f *modfile.File, err error) {
+       if gomodActual, ok := fsys.OverlayPath(gomod); ok {
+               // Don't lock go.mod if it's part of the overlay.
+               // On Plan 9, locking requires chmod, and we don't want to modify any file
+               // in the overlay. See #44700.
+               data, err = os.ReadFile(gomodActual)
+       } else {
+               data, err = lockedfile.Read(gomodActual)
+       }
+       if err != nil {
+               return nil, nil, err
+       }
+
+       f, err = modfile.Parse(gomod, data, fix)
+       if err != nil {
+               // Errors returned by modfile.Parse begin with file:line.
+               return nil, nil, fmt.Errorf("errors parsing go.mod:\n%s\n", err)
+       }
+       if f.Module == nil {
+               // No module declaration. Must add module path.
+               return nil, nil, errors.New("no module declaration in go.mod. To specify the module path:\n\tgo mod edit -module=example.com/mod")
+       }
+
+       return data, f, err
+}
+
 // modFileGoVersion returns the (non-empty) Go version at which the requirements
 // in modFile are interpreted, or the latest Go version if modFile is nil.
 func modFileGoVersion(modFile *modfile.File) string {
@@ -739,3 +767,15 @@ func queryLatestVersionIgnoringRetractions(ctx context.Context, path string) (la
 }
 
 var latestVersionIgnoringRetractionsCache par.Cache // path → queryLatestVersionIgnoringRetractions result
+
+// ToDirectoryPath adds a prefix if necessary so that path in unambiguously
+// an absolute path or a relative path starting with a '.' or '..'
+// path component.
+func ToDirectoryPath(path string) string {
+       if modfile.IsDirectoryPath(path) {
+               return path
+       }
+       // The path is not a relative path or an absolute path, so make it relative
+       // to the current directory.
+       return "./" + filepath.ToSlash(filepath.Clean(path))
+}
index 529c1c0bfd944a4aca0cf4843aa8814187e917f1..657cd060cc1b0724b8a081566e95988e6f10966e 100644 (file)
@@ -1,3 +1,6 @@
+! go mod initwork doesnotexist
+stderr 'go: creating workspace file: no go.mod file exists in directory doesnotexist'
+
 go mod initwork ./a ./b
 cmp go.work go.work.want
 
index 0de4069865d5a53ad40ebb1e02e887e09c799719..001ac7f65cacf77666bf89dbc00ffc58ae455093 100644 (file)
@@ -33,32 +33,36 @@ cmp stdout go.work.want_json
 go mod editwork -print -fmt -workfile unformatted
 cmp stdout formatted
 
+-- m/go.mod --
+module m
+
+go 1.18
 -- go.work.want_initial --
 go 1.18
 
-directory m
+directory ./m
 -- go.work.want_directory_n --
 go 1.18
 
 directory (
-       m
-       n
+       ./m
+       ./n
 )
 -- go.work.want_go_118 --
 go 1.18
 
 directory (
-       m
-       n
+       ./m
+       ./n
 )
 -- go.work.want_dropdirectory_m --
 go 1.18
 
-directory n
+directory ./n
 -- go.work.want_add_replaces --
 go 1.18
 
-directory n
+directory ./n
 
 replace (
        x.1 v1.3.0 => y.1 v1.4.0
@@ -69,9 +73,9 @@ go 1.18
 
 directory (
        ../a
+       ./c
+       ./n
        /b
-       c
-       n
 )
 
 replace (
@@ -83,7 +87,7 @@ go 1.18
 
 directory (
        ../a
-       c
+       ./c
 )
 
 replace (
@@ -95,7 +99,7 @@ go 1.18
 
 directory (
        ../a
-       c
+       ./c
 )
 
 replace x.1 v1.3.0 => y.1 v1.4.0
@@ -104,7 +108,7 @@ go 1.19
 
 directory (
        ../a
-       b
+       ./b
 )
 
 replace x.1 v1.4.0 => ../z
@@ -116,7 +120,7 @@ replace x.1 v1.4.0 => ../z
                        "DiskPath": "../a"
                },
                {
-                       "DiskPath": "b"
+                       "DiskPath": "./b"
                }
        ],
        "Replace": [