added pagination to `v2/<name>/tags/list` endpoint
Signed-off-by: eyjhb <eyjhbb@gmail.com>master
							parent
							
								
									febc8733d2
								
							
						
					
					
						commit
						4da2712b52
					
				|  | @ -3,6 +3,8 @@ package handlers | |||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"net/http" | ||||
| 	"sort" | ||||
| 	"strconv" | ||||
| 
 | ||||
| 	"github.com/distribution/distribution/v3" | ||||
| 	"github.com/distribution/distribution/v3/registry/api/errcode" | ||||
|  | @ -49,6 +51,51 @@ func (th *tagsHandler) GetTags(w http.ResponseWriter, r *http.Request) { | |||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// do pagination if requested
 | ||||
| 	q := r.URL.Query() | ||||
| 	// get entries after latest, if any specified
 | ||||
| 	if lastEntry := q.Get("last"); lastEntry != "" { | ||||
| 		lastEntryIndex := sort.SearchStrings(tags, lastEntry) | ||||
| 
 | ||||
| 		// as`sort.SearchStrings` can return len(tags), if the
 | ||||
| 		// specified `lastEntry` is not found, we need to
 | ||||
| 		// ensure it does not panic when slicing.
 | ||||
| 		if lastEntryIndex == len(tags) { | ||||
| 			tags = []string{} | ||||
| 		} else { | ||||
| 			tags = tags[lastEntryIndex+1:] | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// if no error, means that the user requested `n` entries
 | ||||
| 	if n := q.Get("n"); n != "" { | ||||
| 		maxEntries, err := strconv.Atoi(n) | ||||
| 		if err != nil || maxEntries < 0 { | ||||
| 			th.Errors = append(th.Errors, v2.ErrorCodePaginationNumberInvalid.WithDetail(map[string]string{"n": n})) | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		// if there is requested more than or
 | ||||
| 		// equal to the amount of tags we have,
 | ||||
| 		// then set the request to equal `len(tags)`.
 | ||||
| 		// the reason for the `=`, is so the else
 | ||||
| 		// clause will only activate if there
 | ||||
| 		// are tags left the user needs.
 | ||||
| 		if maxEntries >= len(tags) { | ||||
| 			maxEntries = len(tags) | ||||
| 		} else if maxEntries > 0 { | ||||
| 			// defined in `catalog.go`
 | ||||
| 			urlStr, err := createLinkEntry(r.URL.String(), maxEntries, tags[maxEntries-1]) | ||||
| 			if err != nil { | ||||
| 				th.Errors = append(th.Errors, errcode.ErrorCodeUnknown.WithDetail(err)) | ||||
| 				return | ||||
| 			} | ||||
| 			w.Header().Set("Link", urlStr) | ||||
| 		} | ||||
| 
 | ||||
| 		tags = tags[:maxEntries] | ||||
| 	} | ||||
| 
 | ||||
| 	w.Header().Set("Content-Type", "application/json") | ||||
| 
 | ||||
| 	enc := json.NewEncoder(w) | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ package storage | |||
| import ( | ||||
| 	"context" | ||||
| 	"path" | ||||
| 	"sort" | ||||
| 
 | ||||
| 	"github.com/distribution/distribution/v3" | ||||
| 	storagedriver "github.com/distribution/distribution/v3/registry/storage/driver" | ||||
|  | @ -47,6 +48,10 @@ func (ts *tagStore) All(ctx context.Context) ([]string, error) { | |||
| 		tags = append(tags, filename) | ||||
| 	} | ||||
| 
 | ||||
| 	// there is no guarantee for the order,
 | ||||
| 	// therefore sort before return.
 | ||||
| 	sort.Strings(tags) | ||||
| 
 | ||||
| 	return tags, nil | ||||
| } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue