diff --git a/pkgs/gnolang/gnomod/gnomod.go b/pkgs/gnolang/gnomod/gnomod.go index 82d8a200856..0e7e46ea7f0 100644 --- a/pkgs/gnolang/gnomod/gnomod.go +++ b/pkgs/gnolang/gnomod/gnomod.go @@ -106,6 +106,18 @@ func GnoToGoMod(f File) (*File, error) { }) } + // Since we already fetched and replaced replacement modules + // with `/pkg/gnomod/...` path. + // Ignore leftovers. + var repl []*modfile.Replace + for _, r := range f.Replace { + if !modfile.IsDirectoryPath(r.New.Path) { + continue + } + repl = append(repl, r) + } + f.Replace = repl + return &f, nil } diff --git a/pkgs/gnolang/gnomod/parse.go b/pkgs/gnolang/gnomod/parse.go index aba763ec258..a62eb1cbdc1 100644 --- a/pkgs/gnolang/gnomod/parse.go +++ b/pkgs/gnolang/gnomod/parse.go @@ -2,7 +2,6 @@ package gnomod import ( "fmt" - "path/filepath" "reflect" "strings" @@ -143,42 +142,3 @@ func (f *File) add(errs *modfile.ErrorList, block *modfile.LineBlock, line *modf f.Replace = append(f.Replace, replace) } } - -func parseReplace(filename string, line *modfile.Line, verb string, args []string) (*modfile.Replace, *modfile.Error) { - wrapError := func(err error) *modfile.Error { - return &modfile.Error{ - Filename: filename, - Pos: line.Start, - Err: err, - } - } - errorf := func(format string, args ...interface{}) *modfile.Error { - return wrapError(fmt.Errorf(format, args...)) - } - - if len(args) != 3 || args[1] != "=>" { - return nil, errorf("usage: %s module/path => ../local/directory", verb) - } - s, err := parseString(&args[0]) - if err != nil { - return nil, errorf("invalid quoted string: %v", err) - } - - ns, err := parseString(&args[2]) - if err != nil { - return nil, errorf("invalid quoted string: %v", err) - } - - if !modfile.IsDirectoryPath(ns) { - return nil, errorf("replacement module must be directory path (rooted or starting with ./ or ../)") - } - if filepath.Separator == '/' && strings.Contains(ns, `\`) { - return nil, errorf("replacement directory appears to be Windows path (on a non-windows system)") - } - - return &modfile.Replace{ - Old: module.Version{Path: s, Version: "v0.0.0"}, - New: module.Version{Path: ns}, - Syntax: line, - }, nil -} diff --git a/pkgs/gnolang/gnomod/read.go b/pkgs/gnolang/gnomod/read.go index c752c65913f..75b632cb2e2 100644 --- a/pkgs/gnolang/gnomod/read.go +++ b/pkgs/gnolang/gnomod/read.go @@ -14,6 +14,7 @@ import ( "errors" "fmt" "os" + "path/filepath" "strconv" "strings" "unicode" @@ -661,6 +662,14 @@ func ModulePath(mod []byte) string { return "" // missing module path } +func modulePathMajor(path string) (string, error) { + _, major, ok := module.SplitPathVersion(path) + if !ok { + return "", fmt.Errorf("invalid module path") + } + return major, nil +} + func parseString(s *string) (string, error) { t := *s if strings.HasPrefix(t, `"`) { @@ -706,3 +715,81 @@ func parseVersion(verb string, path string, s *string) (string, error) { *s = cv return *s, nil } + +func parseReplace(filename string, line *modfile.Line, verb string, args []string) (*modfile.Replace, *modfile.Error) { + wrapModPathError := func(modPath string, err error) *modfile.Error { + return &modfile.Error{ + Filename: filename, + Pos: line.Start, + ModPath: modPath, + Verb: verb, + Err: err, + } + } + wrapError := func(err error) *modfile.Error { + return &modfile.Error{ + Filename: filename, + Pos: line.Start, + Err: err, + } + } + errorf := func(format string, args ...interface{}) *modfile.Error { + return wrapError(fmt.Errorf(format, args...)) + } + + arrow := 2 + if len(args) >= 2 && args[1] == "=>" { + arrow = 1 + } + if len(args) < arrow+2 || len(args) > arrow+3 || args[arrow] != "=>" { + return nil, errorf("usage: %s module/path [v1.2.3] => other/module v1.4\n\t or %s module/path [v1.2.3] => ../local/directory", verb, verb) + } + s, err := parseString(&args[0]) + if err != nil { + return nil, errorf("invalid quoted string: %v", err) + } + pathMajor, err := modulePathMajor(s) + if err != nil { + return nil, wrapModPathError(s, err) + } + var v string + if arrow == 2 { + v, err = parseVersion(verb, s, &args[1]) + if err != nil { + return nil, wrapError(err) + } + if err := module.CheckPathMajor(v, pathMajor); err != nil { + return nil, wrapModPathError(s, err) + } + } + ns, err := parseString(&args[arrow+1]) + if err != nil { + return nil, errorf("invalid quoted string: %v", err) + } + nv := "" + if len(args) == arrow+2 { + if !modfile.IsDirectoryPath(ns) { + if strings.Contains(ns, "@") { + return nil, errorf("replacement module must match format 'path version', not 'path@version'") + } + return nil, errorf("replacement module without version must be directory path (rooted or starting with ./ or ../)") + } + if filepath.Separator == '/' && strings.Contains(ns, `\`) { + return nil, errorf("replacement directory appears to be Windows path (on a non-windows system)") + } + } + if len(args) == arrow+3 { + nv, err = parseVersion(verb, ns, &args[arrow+2]) + if err != nil { + return nil, wrapError(err) + } + if modfile.IsDirectoryPath(ns) { + return nil, errorf("replacement module directory path %q cannot have version", ns) + } + } + return &modfile.Replace{ + Old: module.Version{Path: s, Version: v}, + New: module.Version{Path: ns, Version: nv}, + Syntax: line, + }, nil +}