Refactor into package structure

This commit is contained in:
2020-11-11 01:46:48 +01:00
parent 04fa50d9ae
commit 27993e9fa0
13 changed files with 329 additions and 179 deletions

View File

@ -0,0 +1,120 @@
package registry
import (
"hulthe.net/lookbuilding/internal/pkg/semver"
"github.com/heroku/docker-registry-client/registry"
"github.com/opencontainers/go-digest"
"github.com/pkg/errors"
)
type tagListReq struct {
repository string
responder chan<- tagListResp
}
type tagListResp struct {
Data []Tag
Error error
}
type digestReq struct {
repository string
tag string
responder chan<- digestResp
}
type digestResp struct {
Data digest.Digest
Error error
}
type repoCache struct {
Tags []Tag
// Map tags to digests
Digests map[string]digest.Digest
}
type cache struct {
TagListReq chan<- tagListReq
DigestReq chan<- digestReq
}
func newCache(registry registry.Registry) cache {
tagListReq := make(chan tagListReq)
digestReq := make(chan digestReq)
store := map[string]repoCache{}
go func() {
for {
select {
case req := <-tagListReq:
repo, isPresent := store[req.repository]
if isPresent {
// Tag list was already in cache, just return it
req.responder <- tagListResp{Data: repo.Tags}
} else {
// tag list was not in cache, we have to fetch it
tagNames, err := registry.Tags(req.repository)
if err != nil {
req.responder <- tagListResp{
Error: errors.Wrapf(err, `failed to list tags for registry repo "%s"`, req.repository),
}
}
// convert names to Tag{}
var tags []Tag
for _, tagName := range tagNames {
tags = append(tags, Tag{
Name: tagName,
SemVer: semver.ParseTagAsSemVer(tagName),
})
}
// store result in cache
store[req.repository] = repoCache{
Tags: tags,
Digests: map[string]digest.Digest{},
}
req.responder <- tagListResp{
Data: tags,
}
}
case req := <-digestReq:
repo, isPresent := store[req.repository]
if !isPresent {
req.responder <- digestResp{Error: errors.Errorf(
`repo "%s" not present in cache, can't fetch digest'`, req.repository,
)}
}
digest, isPresent := repo.Digests[req.tag]
if isPresent {
req.responder <- digestResp{Data: digest}
} else {
digest, err := registry.ManifestDigest(req.repository, req.tag)
if err != nil {
req.responder <- digestResp{Error: errors.Wrapf(
err, `failed to get digest for repo=%s tag=%s`, req.repository, req.tag,
)}
}
repo.Digests[req.tag] = digest
req.responder <- digestResp{Data: digest}
}
}
}
}()
return cache {
tagListReq,
digestReq,
}
}

View File

@ -0,0 +1,60 @@
package registry
import (
"fmt"
l "hulthe.net/lookbuilding/internal/pkg/logging"
"hulthe.net/lookbuilding/internal/pkg/semver"
"github.com/heroku/docker-registry-client/registry"
"github.com/opencontainers/go-digest"
)
type Tag struct {
Name string
SemVer *semver.Tag
repository string
cache cache
}
type Client struct {
cache cache
}
func (tag Tag) GetDigest() (digest.Digest, error) {
responseCh := make(chan digestResp)
tag.cache.DigestReq <- digestReq{ tag.repository, tag.Name, responseCh }
resp := <-responseCh
return resp.Data, resp.Error
}
func (client Client) GetRepoTags(maybeOwner *string, repository string) ([]Tag, error) {
if maybeOwner != nil {
repository = fmt.Sprintf("%s/%s", *maybeOwner, repository)
}
responseCh := make(chan tagListResp)
client.cache.TagListReq <- tagListReq { repository, responseCh }
resp := <-responseCh
return resp.Data, resp.Error
}
func AnonymousClient() (*Client, error) {
url := "https://registry-1.docker.io/"
username := "" // anonymous
password := "" // anonymous
registry, err := registry.New(url, username, password)
if err != nil {
return nil, err
}
registry.Logf = l.Logger.Infof
client := Client{
cache: newCache(*registry),
}
return &client, nil
}