Add tags implementation

Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
This commit is contained in:
Derek McGowan 2015-05-08 17:40:30 -07:00
parent da05873b7c
commit d92e5b1096
4 changed files with 98 additions and 25 deletions

View file

@ -112,3 +112,10 @@ func parseHTTPErrorResponse(response *http.Response) error {
} }
return &errors return &errors
} }
func handleErrorResponse(resp *http.Response) error {
if resp.StatusCode >= 400 && resp.StatusCode < 500 {
return parseHTTPErrorResponse(resp)
}
return &UnexpectedHTTPStatusError{Status: resp.Status}
}

View file

@ -26,14 +26,10 @@ type httpLayerUpload struct {
} }
func (hlu *httpLayerUpload) handleErrorResponse(resp *http.Response) error { func (hlu *httpLayerUpload) handleErrorResponse(resp *http.Response) error {
switch { if resp.StatusCode == http.StatusNotFound {
case resp.StatusCode == http.StatusNotFound:
return &BlobUploadNotFoundError{Location: hlu.location} return &BlobUploadNotFoundError{Location: hlu.location}
case resp.StatusCode >= 400 && resp.StatusCode < 500:
return parseHTTPErrorResponse(resp)
default:
return &UnexpectedHTTPStatusError{Status: resp.Status}
} }
return handleErrorResponse(resp)
} }
func (hlu *httpLayerUpload) ReadFrom(r io.Reader) (n int64, err error) { func (hlu *httpLayerUpload) ReadFrom(r io.Reader) (n int64, err error) {

View file

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil"
"net/http" "net/http"
"net/url" "net/url"
"strconv" "strconv"
@ -90,7 +91,36 @@ type manifests struct {
} }
func (ms *manifests) Tags() ([]string, error) { func (ms *manifests) Tags() ([]string, error) {
panic("not implemented") u, err := ms.ub.BuildTagsURL(ms.name)
if err != nil {
return nil, err
}
resp, err := ms.client.Get(u)
if err != nil {
return nil, err
}
switch {
case resp.StatusCode == http.StatusOK:
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
tagsResponse := struct {
Tags []string `json:"tags"`
}{}
if err := json.Unmarshal(b, &tagsResponse); err != nil {
return nil, err
}
return tagsResponse.Tags, nil
case resp.StatusCode == http.StatusNotFound:
return nil, nil
default:
return nil, handleErrorResponse(resp)
}
} }
func (ms *manifests) Exists(dgst digest.Digest) (bool, error) { func (ms *manifests) Exists(dgst digest.Digest) (bool, error) {
@ -113,10 +143,8 @@ func (ms *manifests) ExistsByTag(tag string) (bool, error) {
return true, nil return true, nil
case resp.StatusCode == http.StatusNotFound: case resp.StatusCode == http.StatusNotFound:
return false, nil return false, nil
case resp.StatusCode >= 400 && resp.StatusCode < 500:
return false, parseHTTPErrorResponse(resp)
default: default:
return false, &UnexpectedHTTPStatusError{Status: resp.Status} return false, handleErrorResponse(resp)
} }
} }
@ -146,10 +174,8 @@ func (ms *manifests) GetByTag(tag string) (*manifest.SignedManifest, error) {
} }
return &sm, nil return &sm, nil
case resp.StatusCode >= 400 && resp.StatusCode < 500:
return nil, parseHTTPErrorResponse(resp)
default: default:
return nil, &UnexpectedHTTPStatusError{Status: resp.Status} return nil, handleErrorResponse(resp)
} }
} }
@ -174,10 +200,8 @@ func (ms *manifests) Put(m *manifest.SignedManifest) error {
case resp.StatusCode == http.StatusAccepted: case resp.StatusCode == http.StatusAccepted:
// TODO(dmcgowan): Use or check digest header // TODO(dmcgowan): Use or check digest header
return nil return nil
case resp.StatusCode >= 400 && resp.StatusCode < 500:
return parseHTTPErrorResponse(resp)
default: default:
return &UnexpectedHTTPStatusError{Status: resp.Status} return handleErrorResponse(resp)
} }
} }
@ -200,10 +224,8 @@ func (ms *manifests) Delete(dgst digest.Digest) error {
switch { switch {
case resp.StatusCode == http.StatusOK: case resp.StatusCode == http.StatusOK:
return nil return nil
case resp.StatusCode >= 400 && resp.StatusCode < 500:
return parseHTTPErrorResponse(resp)
default: default:
return &UnexpectedHTTPStatusError{Status: resp.Status} return handleErrorResponse(resp)
} }
} }
@ -275,10 +297,8 @@ func (ls *layers) Upload() (distribution.LayerUpload, error) {
startedAt: time.Now(), startedAt: time.Now(),
location: location, location: location,
}, nil }, nil
case resp.StatusCode >= 400 && resp.StatusCode < 500:
return nil, parseHTTPErrorResponse(resp)
default: default:
return nil, &UnexpectedHTTPStatusError{Status: resp.Status} return nil, handleErrorResponse(resp)
} }
} }
@ -327,9 +347,7 @@ func (ls *layers) fetchLayer(dgst digest.Digest) (distribution.Layer, error) {
BlobSum: dgst, BlobSum: dgst,
}, },
} }
case resp.StatusCode >= 400 && resp.StatusCode < 500:
return nil, parseHTTPErrorResponse(resp)
default: default:
return nil, &UnexpectedHTTPStatusError{Status: resp.Status} return nil, handleErrorResponse(resp)
} }
} }

View file

@ -9,6 +9,7 @@ import (
"log" "log"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"strings"
"testing" "testing"
"time" "time"
@ -602,3 +603,54 @@ func TestManifestPut(t *testing.T) {
// TODO(dmcgowan): Check for error cases // TODO(dmcgowan): Check for error cases
} }
func TestManifestTags(t *testing.T) {
repo := "test.example.com/repo/tags/list"
tagsList := []byte(strings.TrimSpace(`
{
"name": "test.example.com/repo/tags/list",
"tags": [
"tag1",
"tag2",
"funtag"
]
}
`))
var m testutil.RequestResponseMap
addPing(&m)
m = append(m, testutil.RequestResponseMapping{
Request: testutil.Request{
Method: "GET",
Route: "/v2/" + repo + "/tags/list",
},
Response: testutil.Response{
StatusCode: http.StatusOK,
Body: tagsList,
Headers: http.Header(map[string][]string{
"Content-Length": {fmt.Sprint(len(tagsList))},
"Last-Modified": {time.Now().Add(-1 * time.Second).Format(time.ANSIC)},
}),
},
})
e, c := testServer(m)
defer c()
r, err := NewRepository(context.Background(), repo, e, &RepositoryConfig{})
if err != nil {
t.Fatal(err)
}
ms := r.Manifests()
tags, err := ms.Tags()
if err != nil {
t.Fatal(err)
}
if len(tags) != 3 {
t.Fatalf("Wrong number of tags returned: %d, expected 3", len(tags))
}
// TODO(dmcgowan): Check array
// TODO(dmcgowan): Check for error cases
}