in registry/handlers/repositories.go [506:612]
func (h *repositoryTagsHandler) HandleGetTags(w http.ResponseWriter, r *http.Request) {
filters, err := filterParamsFromRequest(r)
if err != nil {
h.Errors = append(h.Errors, err)
return
}
var opts []datastore.RepositoryStoreOption
if h.GetRepoCache() != nil {
opts = append(opts, datastore.WithRepositoryCache(h.GetRepoCache()))
}
rStore := datastore.NewRepositoryStore(h.db.Primary(), opts...)
p := h.Repository.Named().Name()
repo, err := rStore.FindByPath(h.Context, p)
if err != nil {
h.Errors = append(h.Errors, errcode.FromUnknownError(err))
return
}
if repo == nil {
h.Errors = append(h.Errors, v2.ErrorCodeNameUnknown.WithDetail(map[string]string{"name": p}))
return
}
tagsList, err := rStore.TagsDetailPaginated(h.Context, repo, filters)
if err != nil {
h.Errors = append(h.Errors, errcode.FromUnknownError(err))
return
}
// Add a link header if there are more entries to retrieve
// NOTE(prozlach): with exact-match filter we get only one or no entries,
// so pagination is not needed.
if len(tagsList) > 0 && filters.ExactName == "" {
filters.LastEntry = tagsList[len(tagsList)-1].Name
filters.PublishedAt = timeToStringMicroPrecision(tagsList[len(tagsList)-1].PublishedAt)
publishedLast := filters.PublishedAt
hasTagsAfter, err := rStore.HasTagsAfterName(h.Context, repo, filters)
if err != nil {
h.Errors = append(h.Errors, errcode.FromUnknownError(err))
return
}
if !hasTagsAfter {
filters.LastEntry = ""
publishedLast = ""
}
filters.BeforeEntry = tagsList[0].Name
filters.PublishedAt = timeToStringMicroPrecision(tagsList[0].PublishedAt)
publishedBefore := filters.PublishedAt
hasTagsBefore, err := rStore.HasTagsBeforeName(h.Context, repo, filters)
if err != nil {
h.Errors = append(h.Errors, errcode.FromUnknownError(err))
return
}
if !hasTagsBefore {
filters.BeforeEntry = ""
publishedBefore = ""
}
urlStr, err := createLinkEntry(r.URL.String(), filters, publishedBefore, publishedLast)
if err != nil {
h.Errors = append(h.Errors, errcode.FromUnknownError(err))
return
}
if urlStr != "" {
w.Header().Set("Link", urlStr)
}
}
w.Header().Set("Content-Type", "application/json")
resp := make([]RepositoryTagResponse, 0, len(tagsList))
for _, t := range tagsList {
d := RepositoryTagResponse{
Name: t.Name,
Digest: t.Digest.String(),
MediaType: t.MediaType,
Size: t.Size,
CreatedAt: timeToString(t.CreatedAt),
PublishedAt: timeToString(t.PublishedAt),
}
if t.ConfigDigest.Valid {
d.ConfigDigest = t.ConfigDigest.Digest.String()
}
if t.UpdatedAt.Valid {
d.UpdatedAt = timeToString(t.UpdatedAt.Time)
}
if t.Referrers != nil {
d.Referrers = make([]RepositoryTagReferrerResponse, 0, len(t.Referrers))
for _, td := range t.Referrers {
d.Referrers = append(d.Referrers, RepositoryTagReferrerResponse{
Digest: td.Digest,
ArtifactType: td.ArtifactType,
})
}
}
resp = append(resp, d)
}
enc := json.NewEncoder(w)
if err := enc.Encode(resp); err != nil {
h.Errors = append(h.Errors, errcode.FromUnknownError(err))
return
}
}