aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/vendor/golang.org/x/mod/modfile/work.go
diff options
context:
space:
mode:
authorMichael Matloob <matloob@golang.org>2021-04-30 18:09:01 -0400
committerMichael Matloob <matloob@golang.org>2021-07-26 21:11:47 +0000
commit3cd15e02ed26d86556cb59ff509a1f5a08bca29e (patch)
tree0ad40a6ff140b6174f3e9dcaa9410b17bd537e40 /src/cmd/vendor/golang.org/x/mod/modfile/work.go
parenta627fcd3c4fdacdc9bbcccdb926e4804ca6d6815 (diff)
downloadgo-3cd15e02ed26d86556cb59ff509a1f5a08bca29e.tar.gz
go-3cd15e02ed26d86556cb59ff509a1f5a08bca29e.zip
[dev.cmdgo] cmd: pull in x/mod on the dev.cmdgo branch
This change changes the requirement on golang.org/x/mod to require the top of the dev.cmdgo branch of that repository. This allows the code on this branch to use the changes on the branch on that repo for parsing go.work files. It also vendors in those changes using go mod vendor. Generated using: go get -d golang.org/x/mod@dev.cmdgo go mod tidy go mod vendor For #45713 Change-Id: I7a20835937c13f90d17c0f39d96b435daec89fba Reviewed-on: https://go-review.googlesource.com/c/go/+/334933 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>
Diffstat (limited to 'src/cmd/vendor/golang.org/x/mod/modfile/work.go')
-rw-r--r--src/cmd/vendor/golang.org/x/mod/modfile/work.go234
1 files changed, 234 insertions, 0 deletions
diff --git a/src/cmd/vendor/golang.org/x/mod/modfile/work.go b/src/cmd/vendor/golang.org/x/mod/modfile/work.go
new file mode 100644
index 0000000000..b1fabff51b
--- /dev/null
+++ b/src/cmd/vendor/golang.org/x/mod/modfile/work.go
@@ -0,0 +1,234 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modfile
+
+import (
+ "fmt"
+ "sort"
+ "strings"
+)
+
+// A WorkFile is the parsed, interpreted form of a go.work file.
+type WorkFile struct {
+ Go *Go
+ Directory []*Directory
+ Replace []*Replace
+
+ Syntax *FileSyntax
+}
+
+// A Directory is a single directory statement.
+type Directory struct {
+ Path string // Directory path of module.
+ ModulePath string // Module path in the comment.
+ Syntax *Line
+}
+
+// ParseWork parses and returns a go.work file.
+//
+// file is the name of the file, used in positions and errors.
+//
+// data is the content of the file.
+//
+// fix is an optional function that canonicalizes module versions.
+// If fix is nil, all module versions must be canonical (module.CanonicalVersion
+// must return the same string).
+func ParseWork(file string, data []byte, fix VersionFixer) (*WorkFile, error) {
+ fs, err := parse(file, data)
+ if err != nil {
+ return nil, err
+ }
+ f := &WorkFile{
+ Syntax: fs,
+ }
+ var errs ErrorList
+
+ for _, x := range fs.Stmt {
+ switch x := x.(type) {
+ case *Line:
+ f.add(&errs, x, x.Token[0], x.Token[1:], fix)
+
+ case *LineBlock:
+ if len(x.Token) > 1 {
+ errs = append(errs, Error{
+ Filename: file,
+ Pos: x.Start,
+ Err: fmt.Errorf("unknown block type: %s", strings.Join(x.Token, " ")),
+ })
+ continue
+ }
+ switch x.Token[0] {
+ default:
+ errs = append(errs, Error{
+ Filename: file,
+ Pos: x.Start,
+ Err: fmt.Errorf("unknown block type: %s", strings.Join(x.Token, " ")),
+ })
+ continue
+ case "directory", "replace":
+ for _, l := range x.Line {
+ f.add(&errs, l, x.Token[0], l.Token, fix)
+ }
+ }
+ }
+ }
+
+ if len(errs) > 0 {
+ return nil, errs
+ }
+ return f, nil
+}
+
+// Cleanup cleans up the file f after any edit operations.
+// To avoid quadratic behavior, modifications like DropRequire
+// clear the entry but do not remove it from the slice.
+// Cleanup cleans out all the cleared entries.
+func (f *WorkFile) Cleanup() {
+ w := 0
+ for _, r := range f.Directory {
+ if r.Path != "" {
+ f.Directory[w] = r
+ w++
+ }
+ }
+ f.Directory = f.Directory[:w]
+
+ w = 0
+ for _, r := range f.Replace {
+ if r.Old.Path != "" {
+ f.Replace[w] = r
+ w++
+ }
+ }
+ f.Replace = f.Replace[:w]
+
+ f.Syntax.Cleanup()
+}
+
+func (f *WorkFile) AddGoStmt(version string) error {
+ if !GoVersionRE.MatchString(version) {
+ return fmt.Errorf("invalid language version string %q", version)
+ }
+ if f.Go == nil {
+ stmt := &Line{Token: []string{"go", version}}
+ f.Go = &Go{
+ Version: version,
+ Syntax: stmt,
+ }
+ // Find the first non-comment-only block that's and add
+ // the go statement before it. That will keep file comments at the top.
+ i := 0
+ for i = 0; i < len(f.Syntax.Stmt); i++ {
+ if _, ok := f.Syntax.Stmt[i].(*CommentBlock); !ok {
+ break
+ }
+ }
+ f.Syntax.Stmt = append(append(f.Syntax.Stmt[:i:i], stmt), f.Syntax.Stmt[i:]...)
+ } else {
+ f.Go.Version = version
+ f.Syntax.updateLine(f.Go.Syntax, "go", version)
+ }
+ return nil
+}
+
+func (f *WorkFile) AddDirectory(diskPath, modulePath string) error {
+ need := true
+ for _, d := range f.Directory {
+ if d.Path == diskPath {
+ if need {
+ d.ModulePath = modulePath
+ f.Syntax.updateLine(d.Syntax, "directory", AutoQuote(diskPath))
+ need = false
+ } else {
+ d.Syntax.markRemoved()
+ *d = Directory{}
+ }
+ }
+ }
+
+ if need {
+ f.AddNewDirectory(diskPath, modulePath)
+ }
+ return nil
+}
+
+func (f *WorkFile) AddNewDirectory(diskPath, modulePath string) {
+ line := f.Syntax.addLine(nil, "directory", AutoQuote(diskPath))
+ f.Directory = append(f.Directory, &Directory{Path: diskPath, ModulePath: modulePath, Syntax: line})
+}
+
+func (f *WorkFile) SetDirectory(dirs []*Directory) {
+ need := make(map[string]string)
+ for _, d := range dirs {
+ need[d.Path] = d.ModulePath
+ }
+
+ for _, d := range f.Directory {
+ if modulePath, ok := need[d.Path]; ok {
+ d.ModulePath = modulePath
+ } else {
+ d.Syntax.markRemoved()
+ *d = Directory{}
+ }
+ }
+
+ // TODO(#45713): Add module path to comment.
+
+ for diskPath, modulePath := range need {
+ f.AddNewDirectory(diskPath, modulePath)
+ }
+ f.SortBlocks()
+}
+
+func (f *WorkFile) DropDirectory(path string) error {
+ for _, d := range f.Directory {
+ if d.Path == path {
+ d.Syntax.markRemoved()
+ *d = Directory{}
+ }
+ }
+ return nil
+}
+
+func (f *WorkFile) AddReplace(oldPath, oldVers, newPath, newVers string) error {
+ return addReplace(f.Syntax, &f.Replace, oldPath, oldVers, newPath, newVers)
+}
+
+func (f *WorkFile) DropReplace(oldPath, oldVers string) error {
+ for _, r := range f.Replace {
+ if r.Old.Path == oldPath && r.Old.Version == oldVers {
+ r.Syntax.markRemoved()
+ *r = Replace{}
+ }
+ }
+ return nil
+}
+
+func (f *WorkFile) SortBlocks() {
+ f.removeDups() // otherwise sorting is unsafe
+
+ for _, stmt := range f.Syntax.Stmt {
+ block, ok := stmt.(*LineBlock)
+ if !ok {
+ continue
+ }
+ sort.SliceStable(block.Line, func(i, j int) bool {
+ return lineLess(block.Line[i], block.Line[j])
+ })
+ }
+}
+
+// removeDups removes duplicate replace directives.
+//
+// Later replace directives take priority.
+//
+// require directives are not de-duplicated. That's left up to higher-level
+// logic (MVS).
+//
+// retract directives are not de-duplicated since comments are
+// meaningful, and versions may be retracted multiple times.
+func (f *WorkFile) removeDups() {
+ removeDups(f.Syntax, nil, &f.Replace)
+}