diff --git a/pkg/api/api.go b/pkg/api/api.go index 1b449c3..a03fd07 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -31,6 +31,7 @@ type vcsPath struct { vcs func(module string) vcs.VCS } +// Option configures an API handler. type Option func(*api) var ( @@ -40,6 +41,7 @@ var ( apiZip = regexp.MustCompile(`^/(?P.*)/@v/(?P.*).zip$`) ) +// New returns a configured http.Handler which implements GOPROXY API. func New(options ...Option) http.Handler { api := &api{log: func(...interface{}) {}} for _, opt := range options { @@ -48,8 +50,13 @@ func New(options ...Option) http.Handler { return api } +// Log configures API to use a specific logger function, such as log.Println, +// testing.T.Log or any other custom logger. func Log(log logger) Option { return func(api *api) { api.log = log } } +// Git configures API to use a specific git client when trying to download a +// repository with the given prefix. Auth string can be a path to the SSK key, +// or a colon-separated username:password string. func Git(prefix string, auth string) Option { a := vcs.Key(auth) if creds := strings.SplitN(auth, ":", 2); len(creds) == 2 { @@ -65,12 +72,14 @@ func Git(prefix string, auth string) Option { } } +// Memory configures API to use in-memory cache for downloaded modules. func Memory() Option { return func(api *api) { api.stores = append(api.stores, store.Memory()) } } +// CacheDir configures API to use a local disk storage for downloaded modules. func CacheDir(dir string) Option { return func(api *api) { api.stores = append(api.stores, store.Disk(dir)) diff --git a/pkg/store/disk.go b/pkg/store/disk.go index 0a4610f..a5d4926 100644 --- a/pkg/store/disk.go +++ b/pkg/store/disk.go @@ -11,6 +11,7 @@ import ( type disk string +// Disk returns a local disk cache that stores files within a given directory. func Disk(dir string) Store { return disk(dir) } func (d disk) Put(ctx context.Context, snapshot Snapshot) error { diff --git a/pkg/store/mem.go b/pkg/store/mem.go index 3efc42e..7a0983f 100644 --- a/pkg/store/mem.go +++ b/pkg/store/mem.go @@ -13,6 +13,7 @@ type memory struct { cache []Snapshot } +// Memory creates an in-memory cache. func Memory() Store { return &memory{} } func (m *memory) Put(ctx context.Context, snapshot Snapshot) error { diff --git a/pkg/store/store.go b/pkg/store/store.go index 6df5e35..7c06729 100644 --- a/pkg/store/store.go +++ b/pkg/store/store.go @@ -7,12 +7,15 @@ import ( "github.com/sixt/gomodproxy/pkg/vcs" ) +// Store is an interface for a typical cache. It allows to put a snapshot and +// to get snapshot of the specific version. type Store interface { Put(ctx context.Context, snapshot Snapshot) error Get(ctx context.Context, module string, version vcs.Version) (Snapshot, error) Close() error } +// Snapshot is a module source code of the speciic version. type Snapshot struct { Module string Version vcs.Version @@ -20,6 +23,7 @@ type Snapshot struct { Data []byte } +// Key returns a snapshot key string that can be used in cache stores. func (s Snapshot) Key() string { return s.Module + "@" + string(s.Version) } diff --git a/pkg/vcs/git.go b/pkg/vcs/git.go index 2510a24..9f26ba4 100644 --- a/pkg/vcs/git.go +++ b/pkg/vcs/git.go @@ -30,6 +30,8 @@ type gitVCS struct { auth Auth } +// NewGit return a go-git VCS client implementation that provides information +// about the specific module using the pgiven authentication mechanism. func NewGit(l logger, module string, auth Auth) VCS { return &gitVCS{log: l, module: module, auth: auth} } diff --git a/pkg/vcs/vcs.go b/pkg/vcs/vcs.go index 77a643e..fd04700 100644 --- a/pkg/vcs/vcs.go +++ b/pkg/vcs/vcs.go @@ -13,11 +13,15 @@ import ( type logger = func(v ...interface{}) +// Version represents a semantic version of a module. type Version string var reSemVer = regexp.MustCompile(`^v\d+\.\d+\.\d+$`) +// IsSemVer returns true if a version string is a semantic version e.g. vX.Y.Z. func (v Version) IsSemVer() bool { return reSemVer.MatchString(string(v)) } + +// Hash returns a commit hash if a version is of a form v0.0.0-timestamp-hash. func (v Version) Hash() string { fields := strings.Split(string(v), "-") if len(fields) != 3 { @@ -26,26 +30,38 @@ func (v Version) Hash() string { return fields[2] } +// Module is a source code snapshot for which one can get the commit timestamp +// or the actual ZIP with the source code in it. type Module interface { Timestamp(ctx context.Context, version Version) (time.Time, error) Zip(ctx context.Context, version Version) (io.ReadCloser, error) } +// VCS is a version control system client. It can list available versions from +// the remote, as well as fetch module data such as timestamp or zip snapshot. type VCS interface { List(ctx context.Context) ([]Version, error) Module } +// Auth defines a typical VCS authentication mechanism, such as SSH key or +// username/password. type Auth struct { Username string Password string Key string } -func NoAuth() Auth { return Auth{} } -func Password(username, password string) Auth { return Auth{Username: username, Password: password} } -func Key(key string) Auth { return Auth{Key: key} } +// NoAuth returns an Auth implementation that uses no authentication at all. +func NoAuth() Auth { return Auth{} } +// Password returns an Auth implementation that authenticate via username and password. +func Password(username, password string) Auth { return Auth{Username: username, Password: password} } + +// Key returns an Auth implementation that uses key file authentication mechanism. +func Key(key string) Auth { return Auth{Key: key} } + +// MetaImports resolved module import path for certain hosts using the special tag. func MetaImports(ctx context.Context, module string) (string, error) { if strings.HasPrefix(module, "github.com/") || strings.HasPrefix(module, "bitbucket.org/") { return module, nil