modfile

Imports

Imports #

"errors"
"fmt"
"path/filepath"
"sort"
"strconv"
"strings"
"unicode"
"golang.org/x/mod/internal/lazyregexp"
"golang.org/x/mod/module"
"golang.org/x/mod/semver"
"fmt"
"sort"
"strings"
"bytes"
"fmt"
"strings"
"bytes"
"errors"
"fmt"
"os"
"strconv"
"strings"
"unicode"
"unicode/utf8"

Constants & Variables

GoVersionRE var #

var GoVersionRE = *ast.CallExpr

ToolchainRE var #

Toolchains must be named beginning with `go1`, like "go1.20.3" or "go1.20.3-gccgo". As a special case, "default" is also permitted. Note that this regexp is a much looser condition than go/version.IsValid, for forward compatibility. (This code has to be work to identify new toolchains even if we tweak the syntax in the future.)

var ToolchainRE = *ast.CallExpr

_COMMENT const #

const _COMMENT

_EOF const #

const _EOF tokenKind = *ast.UnaryExpr

_EOLCOMMENT const #

const _EOLCOMMENT

_IDENT const #

const _IDENT

_STRING const #

const _STRING

deprecatedRE var #

var deprecatedRE = *ast.CallExpr

dontFixRetract var #

errDontFix is returned by a VersionFixer to indicate the version should be left alone, even if it's not canonical.

var dontFixRetract VersionFixer = *ast.FuncLit

laxGoVersionRE var #

var laxGoVersionRE = *ast.CallExpr

moduleStr var #

var moduleStr = *ast.CallExpr

slashSlash var #

var slashSlash = *ast.CallExpr

Type Aliases

ErrorList type #

type ErrorList []Error

VersionFixer type #

type VersionFixer func(path string, version string) (string, error)

tokenKind type #

type tokenKind int

Interfaces

Expr interface #

An Expr represents an input element.

type Expr interface {
Span() (start Position, end Position)
Comment() *Comments
}

Structs

Comment struct #

A Comment represents a single // comment.

type Comment struct {
Start Position
Token string
Suffix bool
}

CommentBlock struct #

A CommentBlock represents a top-level block of comments separate from any rule.

type CommentBlock struct {
Comments
Start Position
}

Comments struct #

Comments collects the comments associated with an expression.

type Comments struct {
Before []Comment
Suffix []Comment
After []Comment
}

Error struct #

type Error struct {
Filename string
Pos Position
Verb string
ModPath string
Err error
}

Exclude struct #

An Exclude is a single exclude statement.

type Exclude struct {
Mod module.Version
Syntax *Line
}

File struct #

A File is the parsed, interpreted form of a go.mod file.

type File struct {
Module *Module
Go *Go
Toolchain *Toolchain
Godebug []*Godebug
Require []*Require
Exclude []*Exclude
Replace []*Replace
Retract []*Retract
Tool []*Tool
Syntax *FileSyntax
}

FileSyntax struct #

A FileSyntax represents an entire go.mod file.

type FileSyntax struct {
Name string
Comments
Stmt []Expr
}

Go struct #

A Go is the go statement.

type Go struct {
Version string
Syntax *Line
}

Godebug struct #

A Godebug is a single godebug key=value statement.

type Godebug struct {
Key string
Value string
Syntax *Line
}

LParen struct #

An LParen represents the beginning of a parenthesized line block. It is a place to store suffix comments.

type LParen struct {
Comments
Pos Position
}

Line struct #

A Line is a single line of tokens.

type Line struct {
Comments
Start Position
Token []string
InBlock bool
End Position
}

LineBlock struct #

A LineBlock is a factored block of lines, like require ( "x" "y" )

type LineBlock struct {
Comments
Start Position
LParen LParen
Token []string
Line []*Line
RParen RParen
}

Module struct #

A Module is the module statement.

type Module struct {
Mod module.Version
Deprecated string
Syntax *Line
}

Position struct #

A Position describes an arbitrary source position in a file, including the file, line, column, and byte offset.

type Position struct {
Line int
LineRune int
Byte int
}

RParen struct #

An RParen represents the end of a parenthesized line block. It is a place to store whole-line (before) comments.

type RParen struct {
Comments
Pos Position
}

Replace struct #

A Replace is a single replace statement.

type Replace struct {
Old module.Version
New module.Version
Syntax *Line
}

Require struct #

A Require is a single require statement.

type Require struct {
Mod module.Version
Indirect bool
Syntax *Line
}

Retract struct #

A Retract is a single retract statement.

type Retract struct {
VersionInterval
Rationale string
Syntax *Line
}

Tool struct #

A Tool is a single tool statement.

type Tool struct {
Path string
Syntax *Line
}

Toolchain struct #

A Toolchain is the toolchain statement.

type Toolchain struct {
Name string
Syntax *Line
}

Use struct #

A Use is a single directory statement.

type Use struct {
Path string
ModulePath string
Syntax *Line
}

VersionInterval struct #

A VersionInterval represents a range of versions with upper and lower bounds. Intervals are closed: both bounds are included. When Low is equal to High, the interval may refer to a single version ('v1.2.3') or an interval ('[v1.2.3, v1.2.3]'); both have the same representation.

type VersionInterval struct {
Low string
High string
}

WorkFile struct #

A WorkFile is the parsed, interpreted form of a go.work file.

type WorkFile struct {
Go *Go
Toolchain *Toolchain
Godebug []*Godebug
Use []*Use
Replace []*Replace
Syntax *FileSyntax
}

input struct #

An input represents a single input file being parsed.

type input struct {
filename string
complete []byte
remaining []byte
tokenStart []byte
token token
pos Position
comments []Comment
file *FileSyntax
parseErrors ErrorList
pre []Expr
post []Expr
}

printer struct #

A printer collects the state during printing of a file or expression.

type printer struct {
bytes.Buffer
comment []Comment
margin int
}

token struct #

type token struct {
kind tokenKind
pos Position
endPos Position
text string
}

Functions

AddComment method #

func (f *File) AddComment(text string)

AddExclude method #

AddExclude adds a exclude statement to the mod file. Errors if the provided version is not a canonical version string

func (f *File) AddExclude(path string, vers string) error

AddGoStmt method #

func (f *WorkFile) AddGoStmt(version string) error

AddGoStmt method #

func (f *File) AddGoStmt(version string) error

AddGodebug method #

AddGodebug sets the first godebug line for key to value, preserving any existing comments for that line and removing all other godebug lines for key. If no line currently exists for key, AddGodebug adds a new line at the end of the last godebug block.

func (f *WorkFile) AddGodebug(key string, value string) error

AddGodebug method #

AddGodebug sets the first godebug line for key to value, preserving any existing comments for that line and removing all other godebug lines for key. If no line currently exists for key, AddGodebug adds a new line at the end of the last godebug block.

func (f *File) AddGodebug(key string, value string) error

AddModuleStmt method #

func (f *File) AddModuleStmt(path string) error

AddNewRequire method #

AddNewRequire adds a new require line for path at version vers at the end of the last require block, regardless of any existing require lines for path.

func (f *File) AddNewRequire(path string, vers string, indirect bool)

AddNewUse method #

func (f *WorkFile) AddNewUse(diskPath string, modulePath string)

AddReplace method #

func (f *WorkFile) AddReplace(oldPath string, oldVers string, newPath string, newVers string) error

AddReplace method #

func (f *File) AddReplace(oldPath string, oldVers string, newPath string, newVers string) error

AddRequire method #

AddRequire sets the first require line for path to version vers, preserving any existing comments for that line and removing all other lines for path. If no line currently exists for path, AddRequire adds a new line at the end of the last require block.

func (f *File) AddRequire(path string, vers string) error

AddRetract method #

AddRetract adds a retract statement to the mod file. Errors if the provided version interval does not consist of canonical version strings

func (f *File) AddRetract(vi VersionInterval, rationale string) error

AddTool method #

AddTool adds a new tool directive with the given path. It does nothing if the tool line already exists.

func (f *File) AddTool(path string) error

AddToolchainStmt method #

func (f *WorkFile) AddToolchainStmt(name string) error

AddToolchainStmt method #

func (f *File) AddToolchainStmt(name string) error

AddUse method #

func (f *WorkFile) AddUse(diskPath string, modulePath string) error

AutoQuote function #

AutoQuote returns s or, if quoting is required for s to appear in a go.mod, the quotation of s.

func AutoQuote(s string) string

Cleanup method #

Cleanup cleans up the file f after any edit operations. To avoid quadratic behavior, modifications like [WorkFile.DropRequire] clear the entry but do not remove it from the slice. Cleanup cleans out all the cleared entries.

func (f *WorkFile) Cleanup()

Cleanup method #

Cleanup cleans up the file syntax x after any edit operations. To avoid quadratic behavior, (*Line).markRemoved marks the line as dead by setting line.Token = nil but does not remove it from the slice in which it appears. After edits have all been indicated, calling Cleanup cleans out the dead lines.

func (x *FileSyntax) Cleanup()

Cleanup method #

Cleanup cleans up the file f after any edit operations. To avoid quadratic behavior, modifications like [File.DropRequire] clear the entry but do not remove it from the slice. Cleanup cleans out all the cleared entries.

func (f *File) Cleanup()

Comment method #

Comment returns the receiver. This isn't useful by itself, but a [Comments] struct is embedded into all the expression implementation types, and this gives each of those a Comment method to satisfy the Expr interface.

func (c *Comments) Comment() *Comments

DropExclude method #

func (f *File) DropExclude(path string, vers string) error

DropGoStmt method #

DropGoStmt deletes the go statement from the file.

func (f *File) DropGoStmt()

DropGoStmt method #

DropGoStmt deletes the go statement from the file.

func (f *WorkFile) DropGoStmt()

DropGodebug method #

func (f *File) DropGodebug(key string) error

DropGodebug method #

func (f *WorkFile) DropGodebug(key string) error

DropReplace method #

func (f *File) DropReplace(oldPath string, oldVers string) error

DropReplace method #

func (f *WorkFile) DropReplace(oldPath string, oldVers string) error

DropRequire method #

func (f *File) DropRequire(path string) error

DropRetract method #

func (f *File) DropRetract(vi VersionInterval) error

DropTool method #

RemoveTool removes a tool directive with the given path. It does nothing if no such tool directive exists.

func (f *File) DropTool(path string) error

DropToolchainStmt method #

DropToolchainStmt deletes the toolchain statement from the file.

func (f *WorkFile) DropToolchainStmt()

DropToolchainStmt method #

DropToolchainStmt deletes the toolchain statement from the file.

func (f *File) DropToolchainStmt()

DropUse method #

func (f *WorkFile) DropUse(path string) error

Error method #

func (e *Error) Error() string

Error method #

func (e ErrorList) Error() string

Error method #

Error is called to report an error. Error does not return: it panics.

func (in *input) Error(s string)

Format function #

Format returns a go.mod file as a byte slice, formatted in standard style.

func Format(f *FileSyntax) []byte

Format method #

func (f *File) Format() ([]byte, error)

IsDirectoryPath function #

IsDirectoryPath reports whether the given path should be interpreted as a directory path. Just like on the go command line, relative paths starting with a '.' or '..' path component and rooted paths are directory paths; the rest are module paths.

func IsDirectoryPath(ns string) bool

ModulePath function #

ModulePath returns the module path from the gomod file text. If it cannot find a module path, it returns an empty string. It is tolerant of unrelated problems in the go.mod file.

func ModulePath(mod []byte) string

MustQuote function #

MustQuote reports whether s must be quoted in order to appear as a single token in a go.mod line.

func MustQuote(s string) bool

Parse function #

Parse parses and returns a go.mod 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 Parse(file string, data []byte, fix VersionFixer) (*File, error)

ParseLax function #

ParseLax is like Parse but ignores unknown statements. It is used when parsing go.mod files other than the main module, under the theory that most statement types we add in the future will only apply in the main module, like exclude and replace, and so we get better gradual deployments if old go commands simply ignore those statements when found in go.mod files in dependencies.

func ParseLax(file string, data []byte, fix VersionFixer) (*File, error)

ParseWork function #

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)

SetRequire method #

SetRequire updates the requirements of f to contain exactly req, preserving the existing block structure and line comment contents (except for 'indirect' markings) for the first requirement on each named module path. The Syntax field is ignored for the requirements in req. Any requirements not already present in the file are added to the block containing the last require line. The requirements in req must specify at most one distinct version for each module path. If any existing requirements may be removed, the caller should call [File.Cleanup] after all edits are complete.

func (f *File) SetRequire(req []*Require)

SetRequireSeparateIndirect method #

SetRequireSeparateIndirect updates the requirements of f to contain the given requirements. Comment contents (except for 'indirect' markings) are retained from the first existing requirement for each module path. Like SetRequire, SetRequireSeparateIndirect adds requirements for new paths in req, updates the version and "// indirect" comment on existing requirements, and deletes requirements on paths not in req. Existing duplicate requirements are deleted. As its name suggests, SetRequireSeparateIndirect puts direct and indirect requirements into two separate blocks, one containing only direct requirements, and the other containing only indirect requirements. SetRequireSeparateIndirect may move requirements between these two blocks when their indirect markings change. However, SetRequireSeparateIndirect won't move requirements from other blocks, especially blocks with comments. If the file initially has one uncommented block of requirements, SetRequireSeparateIndirect will split it into a direct-only and indirect-only block. This aids in the transition to separate blocks.

func (f *File) SetRequireSeparateIndirect(req []*Require)

SetUse method #

func (f *WorkFile) SetUse(dirs []*Use)

SortBlocks method #

func (f *WorkFile) SortBlocks()

SortBlocks method #

func (f *File) SortBlocks()

Span method #

func (x *CommentBlock) Span() (start Position, end Position)

Span method #

func (x *LineBlock) Span() (start Position, end Position)

Span method #

func (x *LParen) Span() (start Position, end Position)

Span method #

func (x *RParen) Span() (start Position, end Position)

Span method #

func (x *FileSyntax) Span() (start Position, end Position)

Span method #

func (x *Line) Span() (start Position, end Position)

Unwrap method #

func (e *Error) Unwrap() error

add method #

add returns the position at the end of s, assuming it starts at p.

func (p Position) add(s string) Position

add method #

func (f *WorkFile) add(errs *ErrorList, line *Line, verb string, args []string, fix VersionFixer)

add method #

func (f *File) add(errs *ErrorList, block *LineBlock, line *Line, verb string, args []string, fix VersionFixer, strict bool)

addLine method #

addLine adds a line containing the given tokens to the file. If the first token of the hint matches the first token of the line, the new line is added at the end of the block containing hint, extracting hint into a new block if it is not yet in one. If the hint is non-nil buts its first token does not match, the new line is added after the block containing hint (or hint itself, if not in a block). If no hint is provided, addLine appends the line to the end of the last block with a matching first token, or to the end of the file if no such block exists.

func (x *FileSyntax) addLine(hint Expr, tokens ...string) *Line

addNewGodebug method #

addNewGodebug adds a new godebug key=value line at the end of the last godebug block, regardless of any existing godebug lines for key.

func (f *WorkFile) addNewGodebug(key string, value string)

addNewGodebug method #

addNewGodebug adds a new godebug key=value line at the end of the last godebug block, regardless of any existing godebug lines for key.

func (f *File) addNewGodebug(key string, value string)

addReplace function #

func addReplace(syntax *FileSyntax, replace *[]*Replace, oldPath string, oldVers string, newPath string, newVers string) error

assignComments method #

assignComments attaches comments to nearby syntax.

func (in *input) assignComments()

checkCanonicalVersion function #

checkCanonicalVersion returns a non-nil error if vers is not a canonical version string or does not match the major version of path. If path is non-empty, the error text suggests a format with a major version corresponding to the path.

func checkCanonicalVersion(path string, vers string) error

commentsAdd function #

func commentsAdd(x []Comment, y []Comment) []Comment

endToken method #

endToken marks the end of an input token. It records the actual token string in tok.text. A single trailing newline (LF or CRLF) will be removed from comment tokens.

func (in *input) endToken(kind tokenKind)

eof method #

eof reports whether the input has reached end of file.

func (in *input) eof() bool

expr method #

func (p *printer) expr(x Expr)

file method #

file formats the given file into the print buffer.

func (p *printer) file(f *FileSyntax)

fixRetract method #

fixRetract applies fix to each retract directive in f, appending any errors to errs. Most versions are fixed as we parse the file, but for retract directives, the relevant module path is the one specified with the module directive, and that might appear at the end of the file (or not at all).

func (f *File) fixRetract(fix VersionFixer, errs *ErrorList)

indent method #

indent returns the position on the current line, in bytes, 0-indexed.

func (p *printer) indent() int

isComment method #

func (k tokenKind) isComment() bool

isEOL method #

isEOL returns whether a token terminates a line.

func (k tokenKind) isEOL() bool

isIdent function #

isIdent reports whether c is an identifier rune. We treat most printable runes as identifier runes, except for a handful of ASCII punctuation characters.

func isIdent(c int) bool

isIndirect function #

isIndirect reports whether line has a "// indirect" comment, meaning it is in go.mod only for its effect on indirect dependencies, so that it can be dropped entirely once the effective version of the indirect dependency reaches the given minimum version.

func isIndirect(line *Line) bool

lex method #

lex is called from the parser to obtain the next input token.

func (in *input) lex() token

lineExcludeLess function #

lineExcludeLess reports whether li should be sorted before lj for lines in an "exclude" block.

func lineExcludeLess(li *Line, lj *Line) bool

lineLess function #

lineLess returns whether li should be sorted before lj. It sorts lexicographically without assigning any special meaning to tokens.

func lineLess(li *Line, lj *Line) bool

lineRetractLess function #

lineRetractLess returns whether li should be sorted before lj for lines in a "retract" block. It treats each line as a version interval. Single versions are compared as if they were intervals with the same low and high version. Intervals are sorted in descending order, first by low version, then by high version, using semver.Compare.

func lineRetractLess(li *Line, lj *Line) bool

markRemoved method #

markRemoved modifies line so that it (and its end-of-line comment, if any) will be dropped by (*FileSyntax).Cleanup.

func (line *Line) markRemoved()

markRemoved method #

func (r *Require) markRemoved()

modulePathMajor function #

func modulePathMajor(path string) (string, error)

newInput function #

func newInput(filename string, data []byte) *input

newline method #

newline ends the current line, flushing end-of-line comments.

func (p *printer) newline()

order method #

order walks the expression adding it and its subexpressions to the preorder and postorder lists.

func (in *input) order(x Expr)

parse function #

parse parses the input file.

func parse(file string, data []byte) (f *FileSyntax, err error)

parseDeprecation function #

parseDeprecation extracts the text of comments on a "module" directive and extracts a deprecation message from that. A deprecation message is contained in a paragraph within a block of comments that starts with "Deprecated:" (case sensitive). The message runs until the end of the paragraph and does not include the "Deprecated:" prefix. If the comment block has multiple paragraphs that start with "Deprecated:", parseDeprecation returns the message from the first.

func parseDeprecation(block *LineBlock, line *Line) string

parseDirectiveComment function #

parseDirectiveComment extracts the text of comments on a directive. If the directive's line does not have comments and is part of a block that does have comments, the block's comments are used.

func parseDirectiveComment(block *LineBlock, line *Line) string

parseFile method #

func (in *input) parseFile()

parseLine method #

func (in *input) parseLine() *Line

parseLineBlock method #

func (in *input) parseLineBlock(start Position, token []string, lparen token) *LineBlock

parseReplace function #

func parseReplace(filename string, line *Line, verb string, args []string, fix VersionFixer) (*Replace, *Error)

parseStmt method #

func (in *input) parseStmt()

parseString function #

func parseString(s *string) (string, error)

parseToFile function #

func parseToFile(file string, data []byte, fix VersionFixer, strict bool) (parsed *File, err error)

parseVersion function #

func parseVersion(verb string, path string, s *string, fix VersionFixer) (string, error)

parseVersionInterval function #

func parseVersionInterval(verb string, path string, args *[]string, fix VersionFixer) (VersionInterval, error)

peek method #

peek returns the kind of the next token returned by lex.

func (in *input) peek() tokenKind

peekPrefix method #

peekPrefix reports whether the remaining input begins with the given prefix.

func (in *input) peekPrefix(prefix string) bool

peekRune method #

peekRune returns the next rune in the input without consuming it.

func (in *input) peekRune() int

printf method #

printf prints to the buffer.

func (p *printer) printf(format string, args ...interface{})

readRune method #

readRune consumes and returns the next rune in the input.

func (in *input) readRune() int

readToken method #

readToken lexes the next token from the text and stores it in in.token.

func (in *input) readToken()

removeDups method #

removeDups removes duplicate exclude, replace and tool directives. Earlier exclude and tool directives take priority. 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 *File) removeDups()

removeDups method #

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 function #

func removeDups(syntax *FileSyntax, exclude *[]*Exclude, replace *[]*Replace, tool *[]*Tool)

reverseComments function #

reverseComments reverses the []Comment list.

func reverseComments(list []Comment)

setIndirect method #

setIndirect sets line to have (or not have) a "// indirect" comment.

func (r *Require) setIndirect(indirect bool)

setVersion method #

func (r *Require) setVersion(v string)

startToken method #

startToken marks the beginning of the next input token. It must be followed by a call to endToken, once the token's text has been consumed using readRune.

func (in *input) startToken()

stringsAdd function #

func stringsAdd(x []string, y []string) []string

tokens method #

func (p *printer) tokens(tokens []string)

trim method #

trim removes trailing spaces and tabs from the current line.

func (p *printer) trim()

updateLine method #

func (x *FileSyntax) updateLine(line *Line, tokens ...string)

Generated with Arrow