mirror of
https://github.com/mayflower/docker-ls.git
synced 2025-11-28 00:01:09 +03:00
141 lines
3.0 KiB
Go
141 lines
3.0 KiB
Go
package lib
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/url"
|
|
"strconv"
|
|
)
|
|
|
|
type RepositoryListResponse struct {
|
|
repositories chan *Repository
|
|
err error
|
|
}
|
|
|
|
type repositoryListJsonResponse struct {
|
|
Repositories *[]string `json:"repositories"`
|
|
}
|
|
|
|
func (r *RepositoryListResponse) Repositories() <-chan *Repository {
|
|
return (r.repositories)
|
|
}
|
|
|
|
func (r *RepositoryListResponse) LastError() error {
|
|
return r.err
|
|
}
|
|
|
|
func (r *RegistryApi) executeListRequest(url *url.URL, initialRequest bool) (response *http.Response, close bool, err error) {
|
|
response, err = r.connector.Get(url)
|
|
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
close = response.Close
|
|
|
|
switch response.StatusCode {
|
|
case http.StatusUnauthorized, http.StatusForbidden:
|
|
err = genericAuthorizationError
|
|
return
|
|
|
|
case http.StatusNotFound:
|
|
if initialRequest {
|
|
err = NotImplementedByRemoteError("registry does not implement repository listings")
|
|
} else {
|
|
err = newInvalidStatusCodeError(response.StatusCode)
|
|
}
|
|
|
|
return
|
|
|
|
case http.StatusOK:
|
|
|
|
default:
|
|
err = newInvalidStatusCodeError(response.StatusCode)
|
|
return
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (r *RegistryApi) iterateRepositoryList(lastApiResponse *http.Response, listResponse *RepositoryListResponse) (apiResponse *http.Response, more bool, err error) {
|
|
requestUrl := r.endpointUrl("v2/_catalog")
|
|
|
|
if lastApiResponse != nil {
|
|
linkHeader := lastApiResponse.Header.Get("link")
|
|
|
|
if linkHeader != "" {
|
|
// This is a hack to work around what looks like a bug in the registry:
|
|
// the supplied link URL currently lacks scheme and host
|
|
scheme, host := requestUrl.Scheme, requestUrl.Host
|
|
|
|
requestUrl, err = parseLinkToNextHeader(linkHeader)
|
|
requestUrl.Scheme = scheme
|
|
requestUrl.Host = host
|
|
}
|
|
|
|
if err != nil {
|
|
return
|
|
}
|
|
} else {
|
|
queryParams := requestUrl.Query()
|
|
queryParams.Set("n", strconv.Itoa(r.pageSize))
|
|
requestUrl.RawQuery = queryParams.Encode()
|
|
}
|
|
|
|
apiResponse, needsClose, err := r.executeListRequest(requestUrl, lastApiResponse == nil)
|
|
|
|
if needsClose {
|
|
defer apiResponse.Body.Close()
|
|
}
|
|
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
more = apiResponse.Header.Get("link") != ""
|
|
|
|
var jsonResponse repositoryListJsonResponse
|
|
decoder := json.NewDecoder(apiResponse.Body)
|
|
err = decoder.Decode(&jsonResponse)
|
|
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
if jsonResponse.Repositories == nil {
|
|
err = genericMalformedResponseError
|
|
return
|
|
}
|
|
|
|
for _, repositoryName := range *jsonResponse.Repositories {
|
|
listResponse.repositories <- newRepository(repositoryName)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (r *RegistryApi) ListRepositories() (response *RepositoryListResponse, err error) {
|
|
response = &RepositoryListResponse{
|
|
repositories: make(chan *Repository, r.pageSize),
|
|
}
|
|
|
|
var apiResponse *http.Response
|
|
apiResponse, more, err := r.iterateRepositoryList(apiResponse, response)
|
|
|
|
go func() {
|
|
for more {
|
|
var err error
|
|
apiResponse, more, err = r.iterateRepositoryList(apiResponse, response)
|
|
|
|
if err != nil {
|
|
response.err = err
|
|
break
|
|
}
|
|
}
|
|
|
|
close(response.repositories)
|
|
}()
|
|
|
|
return
|
|
}
|