diff --git a/pkg/cache/cache.go b/pkg/cache/cache.go index 3143230..d2808ca 100644 --- a/pkg/cache/cache.go +++ b/pkg/cache/cache.go @@ -2,11 +2,13 @@ package cache import "git.yetaga.in/alazyreader/libyear/pkg/libyear" -// Cache isn't concurrency-safe, but we don't care about that right now +// Cache holds maps of strings to Info structs. +// It isn't concurrency-safe, but we don't care about that right now. type Cache struct { items map[string]libyear.Info } +// Get retrives an Info struct from the cache, if it exists. func (c *Cache) Get(k string) libyear.Info { i, ok := c.items[k] if ok { @@ -15,6 +17,7 @@ func (c *Cache) Get(k string) libyear.Info { return libyear.Info{} } +// Set adds an Info struct to the cache. func (c *Cache) Set(k string, v libyear.Info) { if c.items == nil { c.items = make(map[string]libyear.Info) diff --git a/pkg/gomod/gomod.go b/pkg/gomod/gomod.go index 9f98107..502e517 100644 --- a/pkg/gomod/gomod.go +++ b/pkg/gomod/gomod.go @@ -7,26 +7,23 @@ import ( "golang.org/x/mod/modfile" ) -type logger interface { - Logf(f string, s ...interface{}) - Debugf(f string, s ...interface{}) -} - +// 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 } -func isReplaced(module string, replaces []*modfile.Replace) bool { - for i := range replaces { - if module == replaces[i].Old.Path { - return true - } - } - return false +// 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 { @@ -59,3 +56,12 @@ func (g *GoMod) LoadAndComputePairs(filename string) ([]libyear.Pair, error) { } 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 +} diff --git a/pkg/gomod/modproxy.go b/pkg/gomod/modproxy.go index 4e3ce19..02f3be0 100644 --- a/pkg/gomod/modproxy.go +++ b/pkg/gomod/modproxy.go @@ -13,6 +13,7 @@ import ( "git.yetaga.in/alazyreader/libyear/pkg/libyear" ) +// A Queryer holds settings for a type Queryer struct { Root string Client http.Client @@ -25,11 +26,19 @@ type majorVersion struct { version int } +// GetLatestVersion returns the "latest" major version of a module, +// jumping across MVS boundaries: +// i.e. github.com/foo/bar => github.com/foo/bar/v2 in the case of one version bump +// github.com/foo/baz/v2 => github.com/foo/baz/v6 in the case of a large jump +// github.com/foo/quuz/v2 => github.com/foo/quuz/v2 in the case of no jump at all. func (q *Queryer) GetLatestVersion(module string) libyear.Info { latestMod := q.findLatestMajorVersion(module) return q.makeProxyRequest(latestMod + "/@latest") } +// GetVersion returns the proxy's information about a given version of a module. +// `module` in this case is a fully-disambiguated MVS name (github.com/foo/bar/v2), +// and `version` is a version identifier as defined in `https://blog.golang.org/publishing-go-modules#TOC_3.` func (q *Queryer) GetVersion(module string, version string) libyear.Info { if !strings.HasPrefix(version, "v") { return libyear.Info{ @@ -44,9 +53,6 @@ func (q *Queryer) GetVersion(module string, version string) libyear.Info { } // given a module, return the "latest" major version of that module, fully defined -// i.e. github.com/foo/bar => github.com/foo/bar/v2 in the case of one version bump -// github.com/foo/baz/v2 => github.com/foo/baz/v6 in the case of a large jump -// github.com/foo/quuz/v2 => github.com/foo/quuz/v2 in the case of no jump at all! func (q *Queryer) findLatestMajorVersion(module string) string { for { nextModule := incrementMajorVersion(module) @@ -58,6 +64,7 @@ func (q *Queryer) findLatestMajorVersion(module string) string { } } +// handle calling the go module proxy func (q *Queryer) makeProxyRequest(mod string) libyear.Info { if q.Root == "" { q.Root = "https://proxy.golang.org/" diff --git a/pkg/libyear/libyear.go b/pkg/libyear/libyear.go index df45587..1173bd3 100644 --- a/pkg/libyear/libyear.go +++ b/pkg/libyear/libyear.go @@ -5,17 +5,20 @@ import ( "time" ) +// Info defines a version and a commit time for that version type Info struct { Version string // version string Time time.Time // commit time } +// Pair is a set of versions for a dependency (current and newest possible) type Pair struct { Name string Latest Info Current Info } +// Calc returns the summed time distance (as a time.Duration) between a set of Pairs of modules. // TODO: sum can only represent ~290 years before overflowing, but we don't actually need nanosecond precision! // Probably worth switching to hour-based summing here. func Calc(p ...Pair) time.Duration { @@ -26,6 +29,7 @@ func Calc(p ...Pair) time.Duration { return sum } +// DecimalYear conversts a time.Duration (which is in nsec) to a two-decimal-place count of years. func DecimalYear(d time.Duration) string { return fmt.Sprintf("%.2f", float64(d.Truncate(time.Hour)/time.Hour)/float64(8760)) } diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index 01402ea..4098245 100644 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -6,6 +6,7 @@ import ( "os" ) +// Log provices a simple leveled logger type Log struct { quiet bool debug bool @@ -13,6 +14,7 @@ type Log struct { stdOut io.Writer } +// NewLogger returns a new logger (duh) with the given levels and output writers func NewLogger(quiet, debug bool, stdOut, errOut io.Writer) *Log { if stdOut == nil { stdOut = os.Stdout @@ -28,32 +30,38 @@ func NewLogger(quiet, debug bool, stdOut, errOut io.Writer) *Log { } } +// Error logs at the error level func (l *Log) Error(s ...interface{}) { fmt.Fprint(l.errOut, s...) } +// Errorf uses fmt.Fprint formatting func (l *Log) Errorf(f string, s ...interface{}) { - fmt.Fprint(l.errOut, s...) + fmt.Fprintf(l.errOut, f, s...) } +// Log only logs if quiet is false func (l *Log) Log(s ...interface{}) { if !l.quiet { fmt.Fprint(l.stdOut, s...) } } +// Logf uses fmt.Fprint fprmatting func (l *Log) Logf(f string, s ...interface{}) { if !l.quiet { fmt.Fprintf(l.stdOut, f, s...) } } +// Debug logs debug-level logs if debug is true func (l *Log) Debug(s ...interface{}) { if l.debug { fmt.Fprint(l.errOut, s...) } } +// Debugf uses fmt.Fprint fprmatting func (l *Log) Debugf(f string, s ...interface{}) { if l.debug { fmt.Fprintf(l.errOut, f, s...)