Repository: magefile/mage
Pull request #342 (2021-04-05 09:58:42)

Replace godoc.org URLs
[godoc.org](https://godoc.org) now redirects to [pkg.go.dev](https://pkg.go.dev) (see [Redirecting godoc.org requests to pkg.go.dev](https://blog.golang.org/godoc.org-redirect)).

This pull request replaces all godoc.org references with equivalent pkg.go.dev URLs.

natefinch: Hey sorry, can you merge main again when you get the chance, and/or check the box that lets me do it? :) 
JamieEdge: Sure, updated now.
ladydascalie: @natefinch I believe this is ready to go now, just needs workflow approval

Patch:
diff --git a/README.md b/README.md
index eed068d..d96fd02 100644
--- a/README.md
+++ b/README.md
@@ -53,9 +53,10 @@ for discussion of usage, development, etc.
 
 # Documentation
 
-see [magefile.org](https://magefile.org) for full docs
+See [magefile.org](https://magefile.org) for full documentation.
 
-see [godoc.org/github.com/magefile/mage/mage](https://godoc.org/github.com/magefile/mage/mage) for how to use mage as a library.
+See [pkg.go.dev/github.com/magefile/mage/mage](https://pkg.go.dev/github.com/magefile/mage/mage)
+for instructions on how to use Mage as a library.
 
 # Why?
 
diff --git a/mg/deps.go b/mg/deps.go
index cae591d..f0c2509 100644
--- a/mg/deps.go
+++ b/mg/deps.go
@@ -134,6 +134,13 @@ func checkFns(fns []interface{}) []Fn {
 			funcs[i] = fn
 			continue
 		}
+
+		// Check if the target provided is a not function so we can give a clear warning
+		t := reflect.TypeOf(f)
+		if t == nil || t.Kind() != reflect.Func {
+			panic(fmt.Errorf("non-function used as a target dependency: %T. The mg.Deps, mg.SerialDeps and mg.CtxDeps functions accept function names, such as mg.Deps(TargetA, TargetB)", f))
+		}
+
 		funcs[i] = F(f)
 	}
 	return funcs
diff --git a/mg/fn.go b/mg/fn.go
index 5737608..2148766 100644
--- a/mg/fn.go
+++ b/mg/fn.go
@@ -100,8 +100,8 @@ func (f fn) Run(ctx context.Context) error {
 
 func checkF(target interface{}, args []interface{}) (hasContext, isNamespace bool, _ error) {
 	t := reflect.TypeOf(target)
-	if t.Kind() != reflect.Func {
-		return false, false, fmt.Errorf("non-function passed to mg.F: %T", target)
+	if t == nil || t.Kind() != reflect.Func {
+		return false, false, fmt.Errorf("non-function passed to mg.F: %T. The mg.F function accepts function names, such as mg.F(TargetA, \"arg1\", \"arg2\")", target)
 	}
 
 	if t.NumOut() > 1 {
diff --git a/parse/parse.go b/parse/parse.go
index 5ab0070..37df031 100644
--- a/parse/parse.go
+++ b/parse/parse.go
@@ -267,7 +267,7 @@ func Package(path string, files []string) (*PkgInfo, error) {
 
 func getNamedImports(gocmd string, pkgs map[string]string) ([]*Import, error) {
 	var imports []*Import
-	for alias, pkg := range pkgs {
+	for pkg, alias := range pkgs {
 		debug.Printf("getting import package %q, alias %q", pkg, alias)
 		imp, err := getImport(gocmd, pkg, alias)
 		if err != nil {
@@ -411,10 +411,7 @@ func setImports(gocmd string, pi *PkgInfo) error {
 				}
 				if alias != "" {
 					debug.Printf("found %s: %s (%s)", importTag, name, alias)
-					if importNames[alias] != "" {
-						return fmt.Errorf("duplicate import alias: %q", alias)
-					}
-					importNames[alias] = name
+					importNames[name] = alias
 				} else {
 					debug.Printf("found %s: %s", importTag, name)
 					rootImports = append(rootImports, name)
diff --git a/sh/cmd.go b/sh/cmd.go
index 87bb37e..35d232a 100644
--- a/sh/cmd.go
+++ b/sh/cmd.go
@@ -137,7 +137,10 @@ func run(env map[string]string, stdout, stderr io.Writer, cmd string, args ...st
 	for i := range args {
 		quoted = append(quoted, fmt.Sprintf("%q", args[i]));
 	}
-	log.Println("exec:", cmd,  strings.Join(quoted, " "))
+	// To protect against logging from doing exec in global variables
+	if mg.Verbose() {
+		log.Println("exec:", cmd, strings.Join(quoted, " "))
+	}
 	err = c.Run()
 	return CmdRan(err), ExitStatus(err), err
 }
diff --git a/site/content/dependencies/_index.en.md b/site/content/dependencies/_index.en.md
index 857157b..9241111 100644
--- a/site/content/dependencies/_index.en.md
+++ b/site/content/dependencies/_index.en.md
@@ -4,8 +4,8 @@ weight = 30
 +++
 
 Mage supports a makefile-style tree of dependencies using the helper library
-[github.com/magefile/mage/mg](https://godoc.org/github.com/magefile/mage/mg). To
-declare dependencies, pass any number of dependent functions to mg.Deps.
+[github.com/magefile/mage/mg](https://pkg.go.dev/github.com/magefile/mage/mg). To declare dependencies,
+pass any number of dependent functions to mg.Deps.
 
 A dependent function may be any function that has an optional first argument of context.Context, has
 either no return or just an error return, and where the other arguments are all of type string, int,
diff --git a/site/content/filesources/_index.en.md b/site/content/filesources/_index.en.md
index c2f2bd3..d427b7d 100644
--- a/site/content/filesources/_index.en.md
+++ b/site/content/filesources/_index.en.md
@@ -4,7 +4,7 @@ weight = 35
 +++
 
 Mage supports make-like comparisons of file sources and file targets.  Using the
-[target](https://godoc.org/github.com/magefile/mage/target) library, you can
+[target](https://pkg.go.dev/github.com/magefile/mage/target) library, you can
 easily compare the last modified times of a target file or directory with the
 last modified time of the file or directories required to build that target.
 
diff --git a/site/content/libraries/_index.en.md b/site/content/libraries/_index.en.md
index 6d8c8ed..59a2682 100644
--- a/site/content/libraries/_index.en.md
+++ b/site/content/libraries/_index.en.md
@@ -4,9 +4,9 @@ weight = 45
 +++
 
 There are three helper libraries bundled with mage,
-[mg](https://godoc.org/github.com/magefile/mage/mg),
-[sh](https://godoc.org/github.com/magefile/mage/sh), and 
-[target](https://godoc.org/github.com/magefile/mage/target)  
+[mg](https://pkg.go.dev/github.com/magefile/mage/mg),
+[sh](https://pkg.go.dev/github.com/magefile/mage/sh) and 
+[target](https://pkg.go.dev/github.com/magefile/mage/target).
 
 Package `mg` contains mage-specific helpers, such as Deps for declaring
 dependent functions, and functions for returning errors with specific error
diff --git a/site/content/zeroInstall/_index.en.md b/site/content/zeroInstall/_index.en.md
index d239a04..8f71735 100644
--- a/site/content/zeroInstall/_index.en.md
+++ b/site/content/zeroInstall/_index.en.md
@@ -44,8 +44,8 @@ required = ["github.com/magefile/mage/mage"]
 
 ## Use Mage as a library
 
-All of mage's functionality is accessible as a compile-in library.  Checkout
-[godoc.org/github.com/magefile/mage/mage](https://godoc.org/github.com/magefile/mage/mage)
+All of mage's functionality is accessible as a compile-in library.  Check out
+[pkg.go.dev/github.com/magefile/mage/mage](https://pkg.go.dev/github.com/magefile/mage/mage)
 for full details.
 
 Fair warning, the API of mage/mage may change, so be sure to use vendoring.


Test patch:
diff --git a/mage/import_test.go b/mage/import_test.go
index af7d5ff..83949b2 100644
--- a/mage/import_test.go
+++ b/mage/import_test.go
@@ -312,3 +312,57 @@ Error parsing magefiles: error running "go list -f {{.Dir}}||{{.Name}} github.co
 		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actualShortened)
 	}
 }
+
+func TestMageImportsSameNamespaceUniqueTargets(t *testing.T) {
+	stdout := &bytes.Buffer{}
+	stderr := &bytes.Buffer{}
+	inv := Invocation{
+		Dir:    "./testdata/mageimport/samenamespace/uniquetargets",
+		Stdout: stdout,
+		Stderr: stderr,
+		List:   true,
+	}
+
+	code := Invoke(inv)
+	if code != 0 {
+		t.Fatalf("expected to exit with code 0, but got %v, stderr:\n%s", code, stderr)
+	}
+	actual := stdout.String()
+	expected := `
+Targets:
+  samenamespace:build1    
+  samenamespace:build2    
+`[1:]
+
+	if actual != expected {
+		t.Logf("expected: %q", expected)
+		t.Logf("  actual: %q", actual)
+		t.Fatalf("expected:\n%v\n\ngot:\n%v", expected, actual)
+	}
+}
+
+func TestMageImportsSameNamespaceDupTargets(t *testing.T) {
+	stdout := &bytes.Buffer{}
+	stderr := &bytes.Buffer{}
+	inv := Invocation{
+		Dir:    "./testdata/mageimport/samenamespace/duptargets",
+		Stdout: stdout,
+		Stderr: stderr,
+		List:   true,
+	}
+
+	code := Invoke(inv)
+	if code != 1 {
+		t.Fatalf("expected to exit with code 1, but got %v, stderr:\n%s", code, stderr)
+	}
+	actual := stderr.String()
+	expected := `
+Error parsing magefiles: "samenamespace:build" target has multiple definitions: github.com/magefile/mage/mage/testdata/mageimport/samenamespace/duptargets/package1.Build, github.com/magefile/mage/mage/testdata/mageimport/samenamespace/duptargets/package2.Build
+
+`[1:]
+	if actual != expected {
+		t.Logf("expected: %q", expected)
+		t.Logf("  actual: %q", actual)
+		t.Fatalf("expected:\n%v\n\ngot:\n%v", expected, actual)
+	}
+}
diff --git a/mage/testdata/mageimport/samenamespace/duptargets/magefile.go b/mage/testdata/mageimport/samenamespace/duptargets/magefile.go
new file mode 100644
index 0000000..5c58530
--- /dev/null
+++ b/mage/testdata/mageimport/samenamespace/duptargets/magefile.go
@@ -0,0 +1,10 @@
+// +build mage
+
+package sametarget
+
+import (
+	// mage:import samenamespace
+	_ "github.com/magefile/mage/mage/testdata/mageimport/samenamespace/duptargets/package1"
+	// mage:import samenamespace
+	_ "github.com/magefile/mage/mage/testdata/mageimport/samenamespace/duptargets/package2"
+)
diff --git a/mage/testdata/mageimport/samenamespace/duptargets/package1/package1.go b/mage/testdata/mageimport/samenamespace/duptargets/package1/package1.go
new file mode 100644
index 0000000..3f634e7
--- /dev/null
+++ b/mage/testdata/mageimport/samenamespace/duptargets/package1/package1.go
@@ -0,0 +1,7 @@
+package package1
+
+import "fmt"
+
+func Build() {
+	fmt.Println("build")
+}
diff --git a/mage/testdata/mageimport/samenamespace/duptargets/package2/package2.go b/mage/testdata/mageimport/samenamespace/duptargets/package2/package2.go
new file mode 100644
index 0000000..1d7826f
--- /dev/null
+++ b/mage/testdata/mageimport/samenamespace/duptargets/package2/package2.go
@@ -0,0 +1,7 @@
+package package2
+
+import "fmt"
+
+func Build() {
+	fmt.Println("build")
+}
diff --git a/mage/testdata/mageimport/samenamespace/uniquetargets/magefile.go b/mage/testdata/mageimport/samenamespace/uniquetargets/magefile.go
new file mode 100644
index 0000000..aebacbb
--- /dev/null
+++ b/mage/testdata/mageimport/samenamespace/uniquetargets/magefile.go
@@ -0,0 +1,10 @@
+// +build mage
+
+package main
+
+import (
+	// mage:import samenamespace
+	_ "github.com/magefile/mage/mage/testdata/mageimport/samenamespace/uniquetargets/package1"
+	// mage:import samenamespace
+	_ "github.com/magefile/mage/mage/testdata/mageimport/samenamespace/uniquetargets/package2"
+)
diff --git a/mage/testdata/mageimport/samenamespace/uniquetargets/package1/package1.go b/mage/testdata/mageimport/samenamespace/uniquetargets/package1/package1.go
new file mode 100644
index 0000000..ce7488f
--- /dev/null
+++ b/mage/testdata/mageimport/samenamespace/uniquetargets/package1/package1.go
@@ -0,0 +1,7 @@
+package package1
+
+import "fmt"
+
+func Build1() {
+	fmt.Println("build")
+}
diff --git a/mage/testdata/mageimport/samenamespace/uniquetargets/package2/package2.go b/mage/testdata/mageimport/samenamespace/uniquetargets/package2/package2.go
new file mode 100644
index 0000000..7270997
--- /dev/null
+++ b/mage/testdata/mageimport/samenamespace/uniquetargets/package2/package2.go
@@ -0,0 +1,7 @@
+package package2
+
+import "fmt"
+
+func Build2() {
+	fmt.Println("build")
+}
diff --git a/mg/deps_internal_test.go b/mg/deps_internal_test.go
index 5b561bf..cf28e4a 100644
--- a/mg/deps_internal_test.go
+++ b/mg/deps_internal_test.go
@@ -2,6 +2,7 @@ package mg
 
 import (
 	"bytes"
+	"fmt"
 	"log"
 	"os"
 	"strings"
@@ -33,3 +34,23 @@ func bar() {
 }
 
 func baz() {}
+
+func TestDepWasNotInvoked(t *testing.T) {
+	fn1 := func() error {
+		return nil
+	}
+	defer func() {
+		err := recover()
+		if err == nil {
+			t.Fatal("expected panic, but didn't get one")
+		}
+		gotErr := fmt.Sprint(err)
+		wantErr := "non-function used as a target dependency: <nil>. The mg.Deps, mg.SerialDeps and mg.CtxDeps functions accept function names, such as mg.Deps(TargetA, TargetB)"
+		if !strings.Contains(gotErr, wantErr) {
+			t.Fatalf(`expected to get "%s" but got "%s"`, wantErr, gotErr)
+		}
+	}()
+	func(fns ...interface{}) {
+		checkFns(fns)
+	}(fn1())
+}
diff --git a/mg/fn_test.go b/mg/fn_test.go
index 8011167..ee3d0bb 100644
--- a/mg/fn_test.go
+++ b/mg/fn_test.go
@@ -114,6 +114,16 @@ func TestFuncCheck(t *testing.T) {
 	if err == nil {
 		t.Error("expected func(*int) error to be invalid")
 	}
+
+	defer func() {
+		if r := recover(); r !=nil {
+			t.Error("expected a nil function argument to be handled gracefully")
+		}
+	}()
+	_, _, err = checkF(nil, []interface{}{1,2})
+	if err == nil {
+		t.Error("expected a nil function argument to be invalid")
+	}
 }
 
 func TestF(t *testing.T) {