package gomod import ( "os" "git.yetaga.in/alazyreader/libyear/pkg/libyear" "golang.org/x/mod/modfile" ) // GoMod represents a Go Modules parser. // Running LoadAndComputePairs with a filename will return a slice of parsed dependencies. type GoMod struct { IncludeIndirect bool ProxyLoader Queryer Logger logger } // logger is an extremely simple leveled logger type logger interface { Logf(f string, s ...interface{}) Debugf(f string, s ...interface{}) } // LoadAndComputePairs takes a filename of a go.mod file, // runs the resolution algorithm in the provided Querier, // and returns parsed pairs of dependencies and their latest versions. func (g *GoMod) LoadAndComputePairs(filename string) ([]libyear.Pair, error) { b, err := os.ReadFile(filename) if err != nil { return nil, err } f, err := modfile.Parse(filename, b, nil) if err != nil { return nil, err } pairs := []libyear.Pair{} for v := range f.Require { if f.Require[v].Mod.Path != "" && f.Require[v].Mod.Version != "" { if isReplaced(f.Require[v].Mod.Path, f.Replace) { g.Logger.Logf("%s is replaced, skipping...\n", f.Require[v].Mod.Path) continue } if !g.IncludeIndirect && f.Require[v].Indirect { g.Logger.Logf("%s is indirect, skipping...\n", f.Require[v].Mod.Path) continue } latest := g.ProxyLoader.GetLatestVersion(f.Require[v].Mod.Path) current := g.ProxyLoader.GetVersion(f.Require[v].Mod.Path, f.Require[v].Mod.Version) pairs = append(pairs, libyear.Pair{ Name: f.Require[v].Mod.Path, Current: current, Latest: latest, }) } } return pairs, nil } func isReplaced(module string, replaces []*modfile.Replace) bool { for i := range replaces { if module == replaces[i].Old.Path { return true } } return false }