aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/magefile/mage/mg
diff options
context:
space:
mode:
authorChristine Dodrill <me@christine.website>2017-12-13 10:43:58 -0800
committerChristine Dodrill <me@christine.website>2017-12-13 11:42:37 -0800
commit3a21ef192628f6952eaa981bcdf718a35a4b43c7 (patch)
tree9c88a3ddc57ab5014f436ec2c08c96280872632e /vendor/github.com/magefile/mage/mg
parent3b4b6cede9bc30008b0f40989a1564b26e64fd05 (diff)
downloadxesite-3a21ef192628f6952eaa981bcdf718a35a4b43c7.tar.xz
xesite-3a21ef192628f6952eaa981bcdf718a35a4b43c7.zip
convert to go buildpack
Diffstat (limited to 'vendor/github.com/magefile/mage/mg')
-rw-r--r--vendor/github.com/magefile/mage/mg/deps.go166
-rw-r--r--vendor/github.com/magefile/mage/mg/deps_test.go147
-rw-r--r--vendor/github.com/magefile/mage/mg/errors.go51
-rw-r--r--vendor/github.com/magefile/mage/mg/errors_test.go19
-rw-r--r--vendor/github.com/magefile/mage/mg/runtime.go36
5 files changed, 419 insertions, 0 deletions
diff --git a/vendor/github.com/magefile/mage/mg/deps.go b/vendor/github.com/magefile/mage/mg/deps.go
new file mode 100644
index 0000000..30d6edc
--- /dev/null
+++ b/vendor/github.com/magefile/mage/mg/deps.go
@@ -0,0 +1,166 @@
+package mg
+
+import (
+ "context"
+ "fmt"
+ "reflect"
+ "runtime"
+ "strings"
+ "sync"
+
+ "github.com/magefile/mage/types"
+)
+
+type onceMap struct {
+ mu *sync.Mutex
+ m map[string]*onceFun
+}
+
+func (o *onceMap) LoadOrStore(s string, one *onceFun) *onceFun {
+ defer o.mu.Unlock()
+ o.mu.Lock()
+
+ existing, ok := o.m[s]
+ if ok {
+ return existing
+ }
+ o.m[s] = one
+ return one
+}
+
+var onces = &onceMap{
+ mu: &sync.Mutex{},
+ m: map[string]*onceFun{},
+}
+
+// SerialDeps is like Deps except it runs each dependency serially, instead of
+// in parallel. This can be useful for resource intensive dependencies that
+// shouldn't be run at the same time.
+func SerialDeps(fns ...interface{}) {
+ checkFns(fns)
+ ctx := context.Background()
+ for _, f := range fns {
+ runDeps(ctx, f)
+ }
+}
+
+// SerialCtxDeps is like CtxDeps except it runs each dependency serially,
+// instead of in parallel. This can be useful for resource intensive
+// dependencies that shouldn't be run at the same time.
+func SerialCtxDeps(ctx context.Context, fns ...interface{}) {
+ checkFns(fns)
+ for _, f := range fns {
+ runDeps(ctx, f)
+ }
+}
+
+// CtxDeps runs the given functions as dependencies of the calling function.
+// Dependencies must only be of type: github.com/magefile/mage/types.FuncType.
+// The function calling Deps is guaranteed that all dependent functions will be
+// run exactly once when Deps returns. Dependent functions may in turn declare
+// their own dependencies using Deps. Each dependency is run in their own
+// goroutines. Each function is given the context provided if the function
+// prototype allows for it.
+func CtxDeps(ctx context.Context, fns ...interface{}) {
+ checkFns(fns)
+ runDeps(ctx, fns...)
+}
+
+// runDeps assumes you've already called checkFns.
+func runDeps(ctx context.Context, fns ...interface{}) {
+ mu := &sync.Mutex{}
+ var errs []string
+ var exit int
+ wg := &sync.WaitGroup{}
+ for _, f := range fns {
+ fn := addDep(ctx, f)
+ wg.Add(1)
+ go func() {
+ defer func() {
+ if v := recover(); v != nil {
+ mu.Lock()
+ if err, ok := v.(error); ok {
+ exit = changeExit(exit, ExitStatus(err))
+ } else {
+ exit = changeExit(exit, 1)
+ }
+ errs = append(errs, fmt.Sprint(v))
+ mu.Unlock()
+ }
+ wg.Done()
+ }()
+ if err := fn.run(); err != nil {
+ mu.Lock()
+ errs = append(errs, fmt.Sprint(err))
+ exit = changeExit(exit, ExitStatus(err))
+ mu.Unlock()
+ }
+ }()
+ }
+
+ wg.Wait()
+ if len(errs) > 0 {
+ panic(Fatal(exit, strings.Join(errs, "\n")))
+ }
+}
+
+func checkFns(fns []interface{}) {
+ for _, f := range fns {
+ if err := types.FuncCheck(f); err != nil {
+ panic(err)
+ }
+ }
+}
+
+// Deps runs the given functions with the default runtime context
+func Deps(fns ...interface{}) {
+ CtxDeps(context.Background(), fns...)
+}
+
+func changeExit(old, new int) int {
+ if new == 0 {
+ return old
+ }
+ if old == 0 {
+ return new
+ }
+ if old == new {
+ return old
+ }
+ // both different and both non-zero, just set
+ // exit to 1. Nothing more we can do.
+ return 1
+}
+
+func addDep(ctx context.Context, f interface{}) *onceFun {
+ var fn func(context.Context) error
+ if fn = types.FuncTypeWrap(f); fn == nil {
+ // should be impossible, since we already checked this
+ panic("attempted to add a dep that did not match required type")
+ }
+
+ n := name(f)
+ of := onces.LoadOrStore(n, &onceFun{
+ fn: fn,
+ ctx: ctx,
+ })
+ return of
+}
+
+func name(i interface{}) string {
+ return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
+}
+
+type onceFun struct {
+ once sync.Once
+ fn func(context.Context) error
+ ctx context.Context
+}
+
+func (o *onceFun) run() error {
+ var err error
+ o.once.Do(func() {
+ err = o.fn(o.ctx)
+ })
+ return err
+}
diff --git a/vendor/github.com/magefile/mage/mg/deps_test.go b/vendor/github.com/magefile/mage/mg/deps_test.go
new file mode 100644
index 0000000..ea894bb
--- /dev/null
+++ b/vendor/github.com/magefile/mage/mg/deps_test.go
@@ -0,0 +1,147 @@
+package mg_test
+
+import (
+ "errors"
+ "fmt"
+ "testing"
+ "time"
+
+ "github.com/magefile/mage/mg"
+)
+
+func TestDepsRunOnce(t *testing.T) {
+ done := make(chan struct{})
+ f := func() {
+ done <- struct{}{}
+ }
+ go mg.Deps(f, f)
+ select {
+ case <-done:
+ // cool
+ case <-time.After(time.Millisecond * 100):
+ t.Fatal("func not run in a reasonable amount of time.")
+ }
+ select {
+ case <-done:
+ t.Fatal("func run twice!")
+ case <-time.After(time.Millisecond * 100):
+ // cool... this should be plenty of time for the goroutine to have run
+ }
+}
+
+func TestDepsOfDeps(t *testing.T) {
+ ch := make(chan string, 3)
+ // this->f->g->h
+ h := func() {
+ ch <- "h"
+ }
+ g := func() {
+ mg.Deps(h)
+ ch <- "g"
+ }
+ f := func() {
+ mg.Deps(g)
+ ch <- "f"
+ }
+ mg.Deps(f)
+
+ res := <-ch + <-ch + <-ch
+
+ if res != "hgf" {
+ t.Fatal("expected h then g then f to run, but got " + res)
+ }
+}
+
+func TestDepError(t *testing.T) {
+ // TODO: this test is ugly and relies on implementation details. It should
+ // be recreated as a full-stack test.
+
+ f := func() error {
+ return errors.New("ouch!")
+ }
+ defer func() {
+ err := recover()
+ if err == nil {
+ t.Fatal("expected panic, but didn't get one")
+ }
+ actual := fmt.Sprint(err)
+ if "ouch!" != actual {
+ t.Fatalf(`expected to get "ouch!" but got "%s"`, actual)
+ }
+ }()
+ mg.Deps(f)
+}
+
+func TestDepFatal(t *testing.T) {
+ f := func() error {
+ return mg.Fatal(99, "ouch!")
+ }
+ defer func() {
+ v := recover()
+ if v == nil {
+ t.Fatal("expected panic, but didn't get one")
+ }
+ actual := fmt.Sprint(v)
+ if "ouch!" != actual {
+ t.Fatalf(`expected to get "ouch!" but got "%s"`, actual)
+ }
+ err, ok := v.(error)
+ if !ok {
+ t.Fatalf("expected recovered val to be error but was %T", v)
+ }
+ code := mg.ExitStatus(err)
+ if code != 99 {
+ t.Fatalf("Expected exit status 99, but got %v", code)
+ }
+ }()
+ mg.Deps(f)
+}
+
+func TestDepTwoFatal(t *testing.T) {
+ f := func() error {
+ return mg.Fatal(99, "ouch!")
+ }
+ g := func() error {
+ return mg.Fatal(11, "bang!")
+ }
+ defer func() {
+ v := recover()
+ if v == nil {
+ t.Fatal("expected panic, but didn't get one")
+ }
+ actual := fmt.Sprint(v)
+ // order is non-deterministic, so check for both orders
+ if "ouch!\nbang!" != actual && "bang!\nouch!" != actual {
+ t.Fatalf(`expected to get "ouch!" and "bang!" but got "%s"`, actual)
+ }
+ err, ok := v.(error)
+ if !ok {
+ t.Fatalf("expected recovered val to be error but was %T", v)
+ }
+ code := mg.ExitStatus(err)
+ // two different error codes returns, so we give up and just use error
+ // code 1.
+ if code != 1 {
+ t.Fatalf("Expected exit status 1, but got %v", code)
+ }
+ }()
+ mg.Deps(f, g)
+}
+
+func TestDepWithUnhandledFunc(t *testing.T) {
+ defer func() {
+ err := recover()
+ expected := "Invalid type for dependent function: func(string) string. Dependencies must be func(), func() error, func(context.Context) or func(context.Context) error"
+ actual, ok := err.(error)
+ if !ok {
+ t.Fatalf("Expected type string from panic")
+ }
+ if actual.Error() != expected {
+ t.Fatalf("Expected panic %v but got %v", expected, err)
+ }
+ }()
+ var NotValid func(string) string = func(a string) string {
+ return a
+ }
+ mg.Deps(NotValid)
+}
diff --git a/vendor/github.com/magefile/mage/mg/errors.go b/vendor/github.com/magefile/mage/mg/errors.go
new file mode 100644
index 0000000..06a8690
--- /dev/null
+++ b/vendor/github.com/magefile/mage/mg/errors.go
@@ -0,0 +1,51 @@
+package mg
+
+import (
+ "errors"
+ "fmt"
+)
+
+type fatalErr struct {
+ code int
+ error
+}
+
+func (f fatalErr) ExitStatus() int {
+ return f.code
+}
+
+type exitStatus interface {
+ ExitStatus() int
+}
+
+// Fatal returns an error that will cause mage to print out the
+// given args and exit with the given exit code.
+func Fatal(code int, args ...interface{}) error {
+ return fatalErr{
+ code: code,
+ error: errors.New(fmt.Sprint(args...)),
+ }
+}
+
+// Fatalf returns an error that will cause mage to print out the
+// given message and exit with an exit code of 1.
+func Fatalf(code int, format string, args ...interface{}) error {
+ return fatalErr{
+ code: code,
+ error: fmt.Errorf(format, args...),
+ }
+}
+
+// ExitStatus queries the error for an exit status. If the error is nil, it
+// returns 0. If the error does not implement ExitStatus() int, it returns 1.
+// Otherwise it retiurns the value from ExitStatus().
+func ExitStatus(err error) int {
+ if err == nil {
+ return 0
+ }
+ exit, ok := err.(exitStatus)
+ if !ok {
+ return 1
+ }
+ return exit.ExitStatus()
+}
diff --git a/vendor/github.com/magefile/mage/mg/errors_test.go b/vendor/github.com/magefile/mage/mg/errors_test.go
new file mode 100644
index 0000000..ac5e68f
--- /dev/null
+++ b/vendor/github.com/magefile/mage/mg/errors_test.go
@@ -0,0 +1,19 @@
+package mg
+
+import "testing"
+
+func TestFatalExit(t *testing.T) {
+ expected := 99
+ code := ExitStatus(Fatal(expected))
+ if code != expected {
+ t.Fatalf("Expected code %v but got %v", expected, code)
+ }
+}
+
+func TestFatalfExit(t *testing.T) {
+ expected := 99
+ code := ExitStatus(Fatalf(expected, "boo!"))
+ if code != expected {
+ t.Fatalf("Expected code %v but got %v", expected, code)
+ }
+}
diff --git a/vendor/github.com/magefile/mage/mg/runtime.go b/vendor/github.com/magefile/mage/mg/runtime.go
new file mode 100644
index 0000000..8b99613
--- /dev/null
+++ b/vendor/github.com/magefile/mage/mg/runtime.go
@@ -0,0 +1,36 @@
+package mg
+
+import (
+ "os"
+ "path/filepath"
+ "runtime"
+)
+
+// CacheEnv is the environment variable that users may set to change the
+// location where mage stores its compiled binaries.
+const CacheEnv = "MAGEFILE_CACHE"
+
+// verboseEnv is the environment variable that indicates the user requested
+// verbose mode when running a magefile.
+const verboseEnv = "MAGEFILE_VERBOSE"
+
+// Verbose reports whether a magefile was run with the verbose flag.
+func Verbose() bool {
+ return os.Getenv(verboseEnv) != ""
+}
+
+// CacheDir returns the directory where mage caches compiled binaries. It
+// defaults to $HOME/.magefile, but may be overridden by the MAGEFILE_CACHE
+// environment variable.
+func CacheDir() string {
+ d := os.Getenv(CacheEnv)
+ if d != "" {
+ return d
+ }
+ switch runtime.GOOS {
+ case "windows":
+ return filepath.Join(os.Getenv("HOMEDRIVE"), os.Getenv("HOMEPATH"), "magefile")
+ default:
+ return filepath.Join(os.Getenv("HOME"), ".magefile")
+ }
+}