diff --git a/src/cmd/go/internal/get/get.go b/src/cmd/go/internal/get/get.go index f7b2fa96e8..d38350c2a8 100644 --- a/src/cmd/go/internal/get/get.go +++ b/src/cmd/go/internal/get/get.go @@ -193,8 +193,24 @@ func downloadPaths(patterns []string) []string { for _, arg := range patterns { if strings.Contains(arg, "@") { base.Fatalf("go: cannot use path@version syntax in GOPATH mode") + continue + } + + // Guard against 'go get x.go', a common mistake. + // Note that package and module paths may end with '.go', so only print an error + // if the argument has no slash or refers to an existing file. + if strings.HasSuffix(arg, ".go") { + if !strings.Contains(arg, "/") { + base.Errorf("go get %s: arguments must be package or module paths", arg) + continue + } + if fi, err := os.Stat(arg); err == nil && !fi.IsDir() { + base.Errorf("go get: %s exists as a file, but 'go get' requires package arguments", arg) + } } } + base.ExitIfErrors() + var pkgs []string for _, m := range search.ImportPathsQuiet(patterns) { if len(m.Pkgs) == 0 && strings.Contains(m.Pattern(), "...") { diff --git a/src/cmd/go/internal/modget/get.go b/src/cmd/go/internal/modget/get.go index b1193dbfc4..8d740471b0 100644 --- a/src/cmd/go/internal/modget/get.go +++ b/src/cmd/go/internal/modget/get.go @@ -310,6 +310,20 @@ func runGet(cmd *base.Command, args []string) { continue } + // Guard against 'go get x.go', a common mistake. + // Note that package and module paths may end with '.go', so only print an error + // if the argument has no version and either has no slash or refers to an existing file. + if strings.HasSuffix(arg, ".go") && vers == "" { + if !strings.Contains(arg, "/") { + base.Errorf("go get %s: arguments must be package or module paths", arg) + continue + } + if fi, err := os.Stat(arg); err == nil && !fi.IsDir() { + base.Errorf("go get: %s exists as a file, but 'go get' requires package arguments", arg) + continue + } + } + // If no version suffix is specified, assume @upgrade. // If -u=patch was specified, assume @patch instead. if vers == "" { diff --git a/src/cmd/go/testdata/script/get_go_file.txt b/src/cmd/go/testdata/script/get_go_file.txt new file mode 100644 index 0000000000..97e0f1ac92 --- /dev/null +++ b/src/cmd/go/testdata/script/get_go_file.txt @@ -0,0 +1,60 @@ +# Tests Issue #38478 +# Tests that go get in GOPATH mode returns a specific error if the argument +# ends with '.go', and either has no slash or refers to an existing file. + +env GO111MODULE=off + +# argument doesn't have .go suffix +go get test + +# argument has .go suffix, is a file and exists +! go get test.go +stderr 'go get test.go: arguments must be package or module paths' + +# argument has .go suffix, doesn't exist and has no slashes +! go get test_missing.go +stderr 'go get test_missing.go: arguments must be package or module paths' + +# argument has .go suffix, is a file and exists in sub-directory +! go get test/test.go +stderr 'go get: test/test.go exists as a file, but ''go get'' requires package arguments' + +# argument has .go suffix, doesn't exist and has slashes +! go get test/test_missing.go +! stderr 'arguments must be package or module paths' +! stderr 'exists as a file, but ''go get'' requires package arguments' + +# argument has .go suffix, is a symlink and exists +[symlink] symlink test_sym.go -> test.go +[symlink] ! go get test_sym.go +[symlink] stderr 'go get test_sym.go: arguments must be package or module paths' +[symlink] rm test_sym.go + +# argument has .go suffix, is a symlink and exists in sub-directory +[symlink] symlink test/test_sym.go -> test.go +[symlink] ! go get test/test_sym.go +[symlink] stderr 'go get: test/test_sym.go exists as a file, but ''go get'' requires package arguments' +[symlink] rm test_sym.go + +# argument has .go suffix, is a directory and exists +mkdir test_dir.go +! go get test_dir.go +stderr 'go get test_dir.go: arguments must be package or module paths' +rm test_dir.go + +# argument has .go suffix, is a directory and exists in sub-directory +mkdir test/test_dir.go +! go get test/test_dir.go +! stderr 'arguments must be package or module paths' +! stderr 'exists as a file, but ''go get'' requires package arguments' +rm test/test_dir.go + + +-- test.go -- +package main +func main() {println("test")} + + +-- test/test.go -- +package main +func main() {println("test")} diff --git a/src/cmd/go/testdata/script/mod_get_go_file.txt b/src/cmd/go/testdata/script/mod_get_go_file.txt new file mode 100644 index 0000000000..0c7b5dc11c --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_go_file.txt @@ -0,0 +1,68 @@ +# Tests Issue #38478 +# Tests that go get in GOMOD mode returns a specific error if the argument +# ends with '.go', has no version, and either has no slash or refers to an +# existing file. + +env GO111MODULE=on + +# argument doesn't have .go suffix and has no version +! go get test +! stderr 'arguments must be package or module paths' +! stderr 'exists as a file, but ''go get'' requires package arguments' + +# argument has .go suffix and has version +! go get test.go@v1.0.0 +! stderr 'arguments must be package or module paths' +! stderr 'exists as a file, but ''go get'' requires package arguments' + +# argument has .go suffix, is a file and exists +! go get test.go +stderr 'go get test.go: arguments must be package or module paths' + +# argument has .go suffix, doesn't exist and has no slashes +! go get test_missing.go +stderr 'arguments must be package or module paths' + +# argument has .go suffix, is a file and exists in sub-directory +! go get test/test.go +stderr 'go get: test/test.go exists as a file, but ''go get'' requires package arguments' + +# argument has .go suffix, doesn't exist and has slashes +! go get test/test_missing.go +! stderr 'arguments must be package or module paths' +! stderr 'exists as a file, but ''go get'' requires package arguments' + +# argument has .go suffix, is a symlink and exists +[symlink] symlink test_sym.go -> test.go +[symlink] ! go get test_sym.go +[symlink] stderr 'go get test_sym.go: arguments must be package or module paths' +[symlink] rm test_sym.go + +# argument has .go suffix, is a symlink and exists in sub-directory +[symlink] symlink test/test_sym.go -> test.go +[symlink] ! go get test/test_sym.go +[symlink] stderr 'go get: test/test_sym.go exists as a file, but ''go get'' requires package arguments' +[symlink] rm test_sym.go + +# argument has .go suffix, is a directory and exists +mkdir test_dir.go +! go get test_dir.go +stderr 'go get test_dir.go: arguments must be package or module paths' +rm test_dir.go + +# argument has .go suffix, is a directory and exists in sub-directory +mkdir test/test_dir.go +! go get test/test_dir.go +! stderr 'arguments must be package or module paths' +! stderr 'exists as a file, but ''go get'' requires package arguments' +rm test/test_dir.go + + +-- test.go -- +package main +func main() {println("test")} + + +-- test/test.go -- +package main +func main() {println("test")}