From 6e58e47c7bd6672665dc35cce7b1f325d2addd67 Mon Sep 17 00:00:00 2001 From: Dmitri Shuralyov Date: Thu, 1 Jun 2023 19:38:02 -0400 Subject: [PATCH] modfile: improve directory path detection and error text consistency An error text suggests a directory path needs to start with ./ or ../ if it's a relative path, but in reality relative paths with .\ and ..\ prefix (such as those that are used on Windows) are also accepted. Furthermore, a relative path like ./ or ../ is fine, as are ./. and ../., but the cleaner and shorter equivalent relative paths . and .. are reported as if they're not directory paths (even though a module path cannot consist of nothing but dots). Fix those inconsistencies and make IsDirectoryPath report true on "." and ".." paths as expected, and make its documentation clear that a path like "sub/dir", despite being a relative path, is interpreted as a module path. For golang/go#60572. Change-Id: I8fa4a2c66bc83a1ccafc453b96f3bb33dc222cd1 Reviewed-on: https://go-review.googlesource.com/c/mod/+/500335 Reviewed-by: Dmitri Shuralyov Reviewed-by: Bryan Mills Auto-Submit: Dmitri Shuralyov Run-TryBot: Dmitri Shuralyov TryBot-Result: Gopher Robot LUCI-TryBot-Result: Go LUCI --- modfile/rule.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/modfile/rule.go b/modfile/rule.go index e0869fa..35fd1f5 100644 --- a/modfile/rule.go +++ b/modfile/rule.go @@ -542,7 +542,7 @@ func parseReplace(filename string, line *Line, verb string, args []string, fix V 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 ../)") + 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)") @@ -555,7 +555,6 @@ func parseReplace(filename string, line *Line, verb string, args []string, fix V } if IsDirectoryPath(ns) { return nil, errorf("replacement module directory path %q cannot have version", ns) - } } return &Replace{ @@ -679,14 +678,15 @@ func (f *WorkFile) add(errs *ErrorList, line *Line, verb string, args []string, } } -// IsDirectoryPath reports whether the given path should be interpreted -// as a directory path. Just like on the go command line, relative paths +// 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 { // Because go.mod files can move from one system to another, // we check all known path syntaxes, both Unix and Windows. - return strings.HasPrefix(ns, "./") || strings.HasPrefix(ns, "../") || strings.HasPrefix(ns, "/") || - strings.HasPrefix(ns, `.\`) || strings.HasPrefix(ns, `..\`) || strings.HasPrefix(ns, `\`) || + return ns == "." || strings.HasPrefix(ns, "./") || strings.HasPrefix(ns, `.\`) || + ns == ".." || strings.HasPrefix(ns, "../") || strings.HasPrefix(ns, `..\`) || + strings.HasPrefix(ns, "/") || strings.HasPrefix(ns, `\`) || len(ns) >= 2 && ('A' <= ns[0] && ns[0] <= 'Z' || 'a' <= ns[0] && ns[0] <= 'z') && ns[1] == ':' }