Source File
rule.go
Belonging Package
golang.org/x/mod/modfile
package modfile
import (
)
type VersionInterval struct {
Low, High string
}
func ( *File) ( string) error {
if .Syntax == nil {
.Syntax = new(FileSyntax)
}
if .Module == nil {
.Module = &Module{
Mod: module.Version{Path: },
Syntax: .Syntax.addLine(nil, "module", AutoQuote()),
}
} else {
.Module.Mod.Path =
.Syntax.updateLine(.Module.Syntax, "module", AutoQuote())
}
return nil
}
func ( *File) ( string) {
if .Syntax == nil {
.Syntax = new(FileSyntax)
}
.Syntax.Stmt = append(.Syntax.Stmt, &CommentBlock{
Comments: Comments{
Before: []Comment{
{
Token: ,
},
},
},
})
}
type VersionFixer func(path, version string) (string, error)
func ( string, []byte, VersionFixer) (*File, error) {
return parseToFile(, , , true)
}
func ( string, []byte, VersionFixer) (*File, error) {
return parseToFile(, , , false)
}
func ( string, []byte, VersionFixer, bool) (*File, error) {
, := parse(, )
if != nil {
return nil,
}
:= &File{
Syntax: ,
}
var ErrorList
for , := range .Stmt {
switch x := .(type) {
case *Line:
.add(&, nil, , .Token[0], .Token[1:], , )
case *LineBlock:
if len(.Token) > 1 {
if {
= append(, Error{
Filename: ,
Pos: .Start,
Err: fmt.Errorf("unknown block type: %s", strings.Join(.Token, " ")),
})
}
continue
}
switch .Token[0] {
default:
if {
= append(, Error{
Filename: ,
Pos: .Start,
Err: fmt.Errorf("unknown block type: %s", strings.Join(.Token, " ")),
})
}
continue
case "module", "require", "exclude", "replace", "retract":
for , := range .Line {
.add(&, , , .Token[0], .Token, , )
}
}
}
}
if len() > 0 {
return nil,
}
return , nil
}
var GoVersionRE = lazyregexp.New(`^([1-9][0-9]*)\.(0|[1-9][0-9]*)$`)
if ! {
switch {
default:
return
}
}
:= func( string, error) {
* = append(*, Error{
Filename: .Syntax.Name,
Pos: .Start,
ModPath: ,
Verb: ,
Err: ,
})
}
:= func( error) {
* = append(*, Error{
Filename: .Syntax.Name,
Pos: .Start,
Err: ,
})
}
:= func( string, ...interface{}) {
(fmt.Errorf(, ...))
}
switch {
default:
("unknown directive: %s", )
case "go":
if .Go != nil {
("repeated go statement")
return
}
if len() != 1 {
("go directive expects exactly one argument")
return
} else if !GoVersionRE.MatchString([0]) {
("invalid go version '%s': must match format 1.23", [0])
return
}
.Go = &Go{Syntax: }
.Go.Version = [0]
case "module":
if .Module != nil {
("repeated module statement")
return
}
.Module = &Module{Syntax: }
if len() != 1 {
("usage: module module/path")
return
}
, := parseString(&[0])
if != nil {
("invalid quoted string: %v", )
return
}
.Module.Mod = module.Version{Path: }
case "require", "exclude":
if len() != 2 {
("usage: %s module/path v1.2.3", )
return
}
, := parseString(&[0])
if != nil {
("invalid quoted string: %v", )
return
}
, := parseVersion(, , &[1], )
if != nil {
()
return
}
, := modulePathMajor()
if != nil {
()
return
}
if := module.CheckPathMajor(, ); != nil {
(, )
return
}
if == "require" {
.Require = append(.Require, &Require{
Mod: module.Version{Path: , Version: },
Syntax: ,
Indirect: isIndirect(),
})
} else {
.Exclude = append(.Exclude, &Exclude{
Mod: module.Version{Path: , Version: },
Syntax: ,
})
}
case "replace":
:= 2
if len() >= 2 && [1] == "=>" {
= 1
}
if len() < +2 || len() > +3 || [] != "=>" {
("usage: %s module/path [v1.2.3] => other/module v1.4\n\t or %s module/path [v1.2.3] => ../local/directory", , )
return
}
, := parseString(&[0])
if != nil {
("invalid quoted string: %v", )
return
}
, := modulePathMajor()
if != nil {
(, )
return
}
var string
if == 2 {
, = parseVersion(, , &[1], )
if != nil {
()
return
}
if := module.CheckPathMajor(, ); != nil {
(, )
return
}
}
, := parseString(&[+1])
if != nil {
("invalid quoted string: %v", )
return
}
:= ""
if len() == +2 {
if !IsDirectoryPath() {
("replacement module without version must be directory path (rooted or starting with ./ or ../)")
return
}
if filepath.Separator == '/' && strings.Contains(, `\`) {
("replacement directory appears to be Windows path (on a non-windows system)")
return
}
}
if len() == +3 {
, = parseVersion(, , &[+2], )
if != nil {
()
return
}
if IsDirectoryPath() {
("replacement module directory path %q cannot have version", )
return
}
}
.Replace = append(.Replace, &Replace{
Old: module.Version{Path: , Version: },
New: module.Version{Path: , Version: },
Syntax: ,
})
case "retract":
:= parseRetractRationale(, )
, := parseVersionInterval(, &, )
if != nil {
if {
()
return
return
}
}
func ( *Line, bool) {
if isIndirect() == {
return
}
.Token = "// indirect"
return
}
.Token = "// indirect; " +
return
}
func ( string) string {
if MustQuote() {
return strconv.Quote()
}
return
}
func ( string, *[]string, VersionFixer) (VersionInterval, error) {
:= *
if len() == 0 || [0] == "(" {
return VersionInterval{}, fmt.Errorf("expected '[' or version")
}
if [0] != "[" {
, := parseVersion(, "", &[0], )
if != nil {
return VersionInterval{},
}
* = [1:]
return VersionInterval{Low: , High: }, nil
}
= [1:]
if len() == 0 {
return VersionInterval{}, fmt.Errorf("expected version after '['")
}
, := parseVersion(, "", &[0], )
if != nil {
return VersionInterval{},
}
= [1:]
if len() == 0 || [0] != "," {
return VersionInterval{}, fmt.Errorf("expected ',' after version")
}
= [1:]
if len() == 0 {
return VersionInterval{}, fmt.Errorf("expected version after ','")
}
, := parseVersion(, "", &[0], )
if != nil {
return VersionInterval{},
}
= [1:]
if len() == 0 || [0] != "]" {
return VersionInterval{}, fmt.Errorf("expected ']' after version")
}
= [1:]
* =
return VersionInterval{Low: , High: }, nil
}
func ( *string) (string, error) {
:= *
if strings.HasPrefix(, `"`) {
var error
if , = strconv.Unquote(); != nil {
return "",
}
func ( *LineBlock, *Line) string {
:= .Comment()
if != nil && len(.Before) == 0 && len(.Suffix) == 0 {
= .Comment()
}
:= [][]Comment{.Before, .Suffix}
var []string
for , := range {
for , := range {
if !strings.HasPrefix(.Token, "//") {
continue // blank line
}
= append(, strings.TrimSpace(strings.TrimPrefix(.Token, "//")))
}
}
return strings.Join(, "\n")
}
type ErrorList []Error
func ( ErrorList) () string {
:= make([]string, len())
for , := range {
[] = .Error()
}
return strings.Join(, "\n")
}
type Error struct {
Filename string
Pos Position
Verb string
ModPath string
Err error
}
func ( *Error) () string {
var string
= fmt.Sprintf("%s:%d:%d: ", .Filename, .Pos.Line, .Pos.LineRune)
} else if .Pos.Line > 0 {
= fmt.Sprintf("%s:%d: ", .Filename, .Pos.Line)
} else if .Filename != "" {
= fmt.Sprintf("%s: ", .Filename)
}
var string
if .ModPath != "" {
= fmt.Sprintf("%s %s: ", .Verb, .ModPath)
} else if .Verb != "" {
= fmt.Sprintf("%s: ", .Verb)
}
return + + .Err.Error()
}
func ( *Error) () error { return .Err }
func ( string, string, *string, VersionFixer) (string, error) {
, := parseString()
if != nil {
return "", &Error{
Verb: ,
ModPath: ,
Err: &module.InvalidVersionError{
Version: *,
Err: ,
},
}
}
if != nil {
var error
, = (, )
if != nil {
if , := .(*module.ModuleError); {
return "", &Error{
Verb: ,
ModPath: ,
Err: .Err,
}
}
return "",
}
}
if := module.CanonicalVersion(); != "" {
* =
return *, nil
}
return "", &Error{
Verb: ,
ModPath: ,
Err: &module.InvalidVersionError{
Version: ,
Err: errors.New("must be of the form v1.2.3"),
},
}
}
func ( string) (string, error) {
, , := module.SplitPathVersion()
if ! {
return "", fmt.Errorf("invalid module path")
}
return , nil
}
func ( *File) () ([]byte, error) {
return Format(.Syntax), nil
}
func ( *File) () {
:= 0
for , := range .Require {
if .Mod.Path != "" {
.Require[] =
++
}
}
.Require = .Require[:]
= 0
for , := range .Exclude {
if .Mod.Path != "" {
.Exclude[] =
++
}
}
.Exclude = .Exclude[:]
= 0
for , := range .Replace {
if .Old.Path != "" {
.Replace[] =
++
}
}
.Replace = .Replace[:]
= 0
for , := range .Retract {
if .Low != "" || .High != "" {
.Retract[] =
++
}
}
.Retract = .Retract[:]
.Syntax.Cleanup()
}
func ( *File) ( string) error {
if !GoVersionRE.MatchString() {
return fmt.Errorf("invalid language version string %q", )
}
if .Go == nil {
var Expr
if .Module != nil && .Module.Syntax != nil {
= .Module.Syntax
}
.Go = &Go{
Version: ,
Syntax: .Syntax.addLine(, "go", ),
}
} else {
.Go.Version =
.Syntax.updateLine(.Go.Syntax, "go", )
}
return nil
}
func ( *File) (, string) error {
:= true
for , := range .Require {
if .Mod.Path == {
if {
.Mod.Version =
.Syntax.updateLine(.Syntax, "require", AutoQuote(), )
= false
} else {
.Syntax.removeLine(.Syntax)
* = Require{}
}
}
}
if {
.AddNewRequire(, , false)
}
return nil
}
func ( *File) (, string, bool) {
:= .Syntax.addLine(nil, "require", AutoQuote(), )
setIndirect(, )
.Require = append(.Require, &Require{module.Version{Path: , Version: }, , })
}
func ( *File) ( []*Require) {
:= make(map[string]string)
:= make(map[string]bool)
for , := range {
[.Mod.Path] = .Mod.Version
[.Mod.Path] = .Indirect
}
for , := range .Require {
if , := [.Mod.Path]; {
.Mod.Version =
.Indirect = [.Mod.Path]
} else {
* = Require{}
}
}
var []Expr
for , := range .Syntax.Stmt {
switch stmt := .(type) {
case *LineBlock:
if len(.Token) > 0 && .Token[0] == "require" {
var []*Line
for , := range .Line {
if , := parseString(&.Token[0]); == nil && [] != "" {
if len(.Comments.Before) == 1 && len(.Comments.Before[0].Token) == 0 {
.Comments.Before = .Comments.Before[:0]
}
.Token[1] = []
delete(, )
setIndirect(, [])
= append(, )
}
}
if len() == 0 {
continue // drop stmt
}
.Line =
}
case *Line:
if len(.Token) > 0 && .Token[0] == "require" {
if , := parseString(&.Token[1]); == nil && [] != "" {
.Token[2] = []
delete(, )
setIndirect(, [])
} else {
continue // drop stmt
}
}
}
= append(, )
}
.Syntax.Stmt =
for , := range {
.AddNewRequire(, , [])
}
.SortBlocks()
}
func ( *File) ( string) error {
for , := range .Require {
if .Mod.Path == {
.Syntax.removeLine(.Syntax)
* = Require{}
}
}
return nil
}
func ( *File) (, string) error {
var *Line
for , := range .Exclude {
if .Mod.Path == && .Mod.Version == {
return nil
}
if .Mod.Path == {
= .Syntax
}
}
.Exclude = append(.Exclude, &Exclude{Mod: module.Version{Path: , Version: }, Syntax: .Syntax.addLine(, "exclude", AutoQuote(), )})
return nil
}
func ( *File) (, string) error {
for , := range .Exclude {
if .Mod.Path == && .Mod.Version == {
.Syntax.removeLine(.Syntax)
* = Exclude{}
}
}
return nil
}
func ( *File) (, , , string) error {
:= true
:= module.Version{Path: , Version: }
:= module.Version{Path: , Version: }
:= []string{"replace", AutoQuote()}
if != "" {
= append(, )
}
= append(, "=>", AutoQuote())
if != "" {
= append(, )
}
var *Line
for , := range .Replace {
if .Old.Path == && ( == "" || .Old.Version == ) {
.New =
.Syntax.updateLine(.Syntax, ...)
= false
continue
.Syntax.removeLine(.Syntax)
* = Replace{}
}
if .Old.Path == {
= .Syntax
}
}
if {
.Replace = append(.Replace, &Replace{Old: , New: , Syntax: .Syntax.addLine(, ...)})
}
return nil
}
func ( *File) (, string) error {
for , := range .Replace {
if .Old.Path == && .Old.Version == {
.Syntax.removeLine(.Syntax)
* = Replace{}
}
}
return nil
}
func ( *File) ( VersionInterval, string) error {
:= &Retract{
VersionInterval: ,
}
if .Low == .High {
.Syntax = .Syntax.addLine(nil, "retract", AutoQuote(.Low))
} else {
.Syntax = .Syntax.addLine(nil, "retract", "[", AutoQuote(.Low), ",", AutoQuote(.High), "]")
}
if != "" {
for , := range strings.Split(, "\n") {
:= Comment{Token: "// " + }
.Syntax.Comment().Before = append(.Syntax.Comment().Before, )
}
}
return nil
}
func ( *File) ( VersionInterval) error {
for , := range .Retract {
if .VersionInterval == {
.Syntax.removeLine(.Syntax)
* = Retract{}
}
}
return nil
}
func ( *File) () {
.removeDups() // otherwise sorting is unsafe
for , := range .Syntax.Stmt {
, := .(*LineBlock)
if ! {
continue
}
:= lineLess
if .Token[0] == "retract" {
= lineRetractLess
}
sort.SliceStable(.Line, func(, int) bool {
return (.Line[], .Line[])
})
}
}
![]() |
The pages are generated with Golds v0.3.2-preview. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |