@@ -48,6 +48,7 @@ type GoParser struct {
4848 files map [string ][]byte
4949 exclues []* regexp.Regexp
5050 cgoPkgs map [string ]bool // CGO packages
51+ workDirs map [string ]bool // directories that are in go.work scope
5152}
5253
5354type moduleInfo struct {
@@ -97,10 +98,33 @@ func newGoParser(name string, homePageDir string, opts Options) *GoParser {
9798}
9899
99100func (p * GoParser ) collectGoMods (startDir string ) error {
100- hasGoWork := false
101+ var workFiles []string
102+ err := filepath .Walk (startDir , func (path string , info fs.FileInfo , err error ) error {
103+ if err != nil || ! strings .HasSuffix (path , "go.work" ) {
104+ return nil
105+ }
106+ workFiles = append (workFiles , path )
107+ return nil
108+ })
109+ if err != nil {
110+ return err
111+ }
112+
113+ p .workDirs = make (map [string ]bool )
114+ for _ , workPath := range workFiles {
115+ wf , err := parseGoWork (workPath )
116+ if err != nil {
117+ fmt .Fprintf (os .Stderr , "failed to parse go.work file %s: %v\n " , workPath , err )
118+ continue
119+ }
120+ for _ , useDir := range wf .UseDirs {
121+ p .workDirs [useDir ] = true
122+ }
123+ }
124+ fmt .Printf ("go work effective dirs: %v\n " , p .workDirs )
101125 deps := map [string ]string {}
102126 var cgoPkgs map [string ]bool
103- err : = filepath .Walk (startDir , func (path string , info fs.FileInfo , err error ) error {
127+ err = filepath .Walk (startDir , func (path string , info fs.FileInfo , err error ) error {
104128 if err != nil || ! strings .HasSuffix (path , "go.mod" ) {
105129 return nil
106130 }
@@ -117,7 +141,7 @@ func (p *GoParser) collectGoMods(startDir string) error {
117141 p .repo .Modules [name ] = newModule (name , rel )
118142 p .modules = append (p .modules , newModuleInfo (name , rel , name ))
119143
120- deps , hasGoWork , cgoPkgs , err = getDeps (filepath .Dir (path ), hasGoWork )
144+ deps , cgoPkgs , err = getDeps (filepath .Dir (path ), p . workDirs )
121145 if err != nil {
122146 return err
123147 }
@@ -161,9 +185,21 @@ type dep struct {
161185 CgoFiles []string `json:"CgoFiles"`
162186}
163187
164- func getDeps (dir string , goWork bool ) (a map [string ]string , hasGoWork bool , cgoPkgs map [string ]bool , err error ) {
188+ func getDeps (dir string , workDirs map [ string ] bool ) (a map [string ]string , cgoPkgs map [string ]bool , err error ) {
165189 cgoPkgs = make (map [string ]bool )
166- // run go mod tidy first to ensure all dependencies are resolved
190+ absDir , err := filepath .Abs (dir )
191+ if err != nil {
192+ return nil , cgoPkgs , fmt .Errorf ("failed to get absolute path: %w" , err )
193+ }
194+
195+ inWorkSpace := false
196+ for workDir := range workDirs {
197+ if absDir == workDir || strings .HasPrefix (absDir , workDir + string (filepath .Separator )) {
198+ inWorkSpace = true
199+ break
200+ }
201+ }
202+
167203 cmd := exec .Command ("go" , "mod" , "tidy" , "-e" )
168204 cmd .Dir = dir
169205 cmd .Env = append (os .Environ (), "GONOSUMDB=*" )
@@ -176,16 +212,13 @@ func getDeps(dir string, goWork bool) (a map[string]string, hasGoWork bool, cgoP
176212 cmd .Env = append (os .Environ (), "GOSUMDB=off" )
177213 output , err = cmd .CombinedOutput ()
178214 if err != nil {
179- return nil , hasGoWork , cgoPkgs , fmt .Errorf ("failed to execute 'go mod tidy', err: %v, output: %s" , err , string (output ))
215+ return nil , cgoPkgs , fmt .Errorf ("failed to execute 'go mod tidy', err: %v, output: %s" , err , string (output ))
180216 }
181217 }
182218 if hasNoDeps (filepath .Join (dir , "go.mod" )) {
183- return map [string ]string {}, hasGoWork , cgoPkgs , nil
219+ return map [string ]string {}, cgoPkgs , nil
184220 }
185- // -mod=mod to use go mod when go mod is inconsistent with go vendor
186- // if go.work exist, it's no need to set -mod=mod
187- if _ , err = os .Stat (filepath .Join (dir , "go.work" )); err == nil || goWork {
188- hasGoWork = true
221+ if inWorkSpace {
189222 cmd = exec .Command ("go" , "list" , "-e" , "-json" , "all" )
190223 } else {
191224 cmd = exec .Command ("go" , "list" , "-e" , "-json" , "-mod=mod" , "all" )
@@ -194,12 +227,12 @@ func getDeps(dir string, goWork bool) (a map[string]string, hasGoWork bool, cgoP
194227 cmd .Env = append (os .Environ (), "GOSUMDB=off" )
195228 output , err = cmd .CombinedOutput ()
196229 if err != nil {
197- return nil , hasGoWork , cgoPkgs , fmt .Errorf ("failed to execute 'go list -json all', err: %v, output: %s, cmd string: %s, dir: %s" , err , string (output ), cmd .String (), dir )
230+ return nil , cgoPkgs , fmt .Errorf ("failed to execute 'go list -json all', err: %v, output: %s, cmd string: %s, dir: %s" , err , string (output ), cmd .String (), dir )
198231 }
199232 // ignore content until first open
200233 index := strings .Index (string (output ), "{" )
201234 if index == - 1 {
202- return nil , hasGoWork , cgoPkgs , fmt .Errorf ("failed to find '{' in output, output: %s" , string (output ))
235+ return nil , cgoPkgs , fmt .Errorf ("failed to find '{' in output, output: %s" , string (output ))
203236 }
204237 if index > 0 {
205238 log .Info ("go list skip prefix, output: %s" , string (output [:index ]))
@@ -213,7 +246,7 @@ func getDeps(dir string, goWork bool) (a map[string]string, hasGoWork bool, cgoP
213246 if err .Error () == "EOF" {
214247 break
215248 }
216- return nil , hasGoWork , cgoPkgs , fmt .Errorf ("failed to decode json: %v, output: %s" , err , string (output ))
249+ return nil , cgoPkgs , fmt .Errorf ("failed to decode json: %v, output: %s" , err , string (output ))
217250 }
218251 module := mod .Module
219252 // golang internal package, ignore it.
@@ -239,7 +272,7 @@ func getDeps(dir string, goWork bool) (a map[string]string, hasGoWork bool, cgoP
239272 }
240273 }
241274 }
242- return deps , hasGoWork , cgoPkgs , nil
275+ return deps , cgoPkgs , nil
243276}
244277
245278// ParseRepo parse the entiry repo from homePageDir recursively until end
0 commit comments