@@ -12,6 +12,10 @@ import (
1212
1313// Open the go.mod file in the given directory
1414func Open (dir string ) (m * modfile.File , err error ) {
15+ if dir , err = FindModuleRoot (dir ); err != nil {
16+ return m , err
17+ }
18+
1519 goModPath := filepath .Join (dir , "go.mod" )
1620
1721 goModBytes , err := ioutil .ReadFile (goModPath )
@@ -100,6 +104,10 @@ func Mutate(dir string, mutation func(*modfile.File) error) (err error) {
100104func Replace (dir string , m * modfile.File ) (err error ) {
101105 m .Cleanup ()
102106
107+ if dir , err = FindModuleRoot (dir ); err != nil {
108+ return err
109+ }
110+
103111 goModPath := filepath .Join (dir , "go.mod" )
104112
105113 out , err := m .Format ()
@@ -130,3 +138,32 @@ func Print(m *modfile.File) (s string, err error) {
130138
131139 return string (out ), nil
132140}
141+
142+ // FindModuleRoot pulled from: https://github.com/golang/go/blob/88e564edb13f1596c12ad16d5fd3c7ac7deac855/src/cmd/dist/build.go#L1595
143+ func FindModuleRoot (dir string ) (cleaned string , err error ) {
144+ if dir == "" {
145+ return "" , errors .New ("cannot located go.mod from a blank directory path" )
146+ }
147+
148+ if cleaned , err = filepath .Abs (filepath .Clean (dir )); err != nil {
149+ return "" , errors .Wrap (err , "failed to determined absolute path to directory" )
150+ }
151+
152+ // Look for enclosing go.mod.
153+ for {
154+ gomod := filepath .Join (cleaned , "go.mod" )
155+ if fi , err := os .Stat (gomod ); err == nil && ! fi .IsDir () {
156+ return cleaned , nil
157+ }
158+
159+ d := filepath .Dir (cleaned )
160+
161+ if d == cleaned {
162+ break
163+ }
164+
165+ cleaned = d
166+ }
167+
168+ return "" , errors .Errorf ("go.mod not found: %s" , dir )
169+ }
0 commit comments