diff --git a/mg/deps.go b/mg/deps.go index bed1a97..baf1bef 100644 --- a/mg/deps.go +++ b/mg/deps.go @@ -44,11 +44,26 @@ func (o *onceMap) LoadOrStore(f Fn) *onceFun { return one } +func (o *onceMap) Reset() { + o.mu.Lock() + defer o.mu.Unlock() + + o.m = map[onceKey]*onceFun{} +} + var onces = &onceMap{ mu: &sync.Mutex{}, m: map[onceKey]*onceFun{}, } +// ResetDeps clears the dependency cache used by Deps, CtxDeps, SerialDeps, and +// SerialCtxDeps. It is intended for tests that need to run the same dependencies +// more than once in a single process. Do not call ResetDeps while dependencies +// are running. +func ResetDeps() { + onces.Reset() +} + // 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. diff --git a/mg/deps_test.go b/mg/deps_test.go index fe39bbb..07aba82 100644 --- a/mg/deps_test.go +++ b/mg/deps_test.go @@ -29,6 +29,25 @@ func TestDepsRunOnce(t *testing.T) { } } +func TestResetDepsAllowsDependenciesToRunAgain(t *testing.T) { + var calls int64 + f := func() { + atomic.AddInt64(&calls, 1) + } + + Deps(f) + Deps(f) + if calls != 1 { + t.Fatalf("expected dependency to run once before reset, ran %d times", calls) + } + + ResetDeps() + Deps(f) + if calls != 2 { + t.Fatalf("expected dependency to run again after reset, ran %d times", calls) + } +} + func TestDepsOfDeps(t *testing.T) { ch := make(chan string, 3) // this->f->g->h