diff --git a/main.go b/main.go index 2115b07..4d6059c 100644 --- a/main.go +++ b/main.go @@ -210,12 +210,21 @@ func showImageInfo(c *cli.Context) error { if err != nil { return cli.NewExitError(err.Error(), 1) } + tagDetail, err := r.ImageTagDetail(imgName, tag) + if err != nil { + return cli.NewExitError(err.Error(), 1) + } fmt.Printf("Image: %s:%s\n", imgName, tag) + fmt.Printf("Architecture: %s\n", tagDetail.Architecture) fmt.Printf("Size: %d\n", manifest.Config.Size) fmt.Println("Layers:") for _, layer := range manifest.Layers { fmt.Printf("\t%s\t%d\n", layer.Digest, layer.Size) } + fmt.Println("History:") + for _, historyInfo := range tagDetail.History { + fmt.Printf("\t%s\n", historyInfo.V1Compatibility) + } return nil } diff --git a/registry/registry.go b/registry/registry.go index 8f22558..85d2b3a 100644 --- a/registry/registry.go +++ b/registry/registry.go @@ -10,6 +10,7 @@ import ( ) const ACCEPT_HEADER = "application/vnd.docker.distribution.manifest.v2+json" +const ACCEPT_HEADER_V1 = "application/vnd.docker.distribution.manifest.v1+json" const CREDENTIALS_FILE = ".credentials" type Registry struct { @@ -40,6 +41,23 @@ type LayerInfo struct { Digest string `json:"digest"` } +type ImageTagDetail struct { + SchemaVersion int64 `json:"schemaVersion"` + Name string `json:"name"` + Tag string `json:"tag"` + Architecture string `json:"architecture"` + FsLayers []fsLayerInfo `json:"fsLayers"` + History []historyInfo `json:"history"` +} + +type fsLayerInfo struct { + BlobSum string `json:"blobSum"` +} + +type historyInfo struct { + V1Compatibility string `json:"v1Compatibility"` +} + func NewRegistry() (Registry, error) { r := Registry{} if _, err := os.Stat(CREDENTIALS_FILE); os.IsNotExist(err) { @@ -136,6 +154,34 @@ func (r Registry) ImageManifest(image string, tag string) (ImageManifest, error) } +func (r Registry) ImageTagDetail(image string, tag string) (ImageTagDetail, error) { + var imageTagDetail ImageTagDetail + client := &http.Client{} + + url := fmt.Sprintf("%s/repository/%s/v2/%s/manifests/%s", r.Host, r.Repository, image, tag) + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return imageTagDetail, err + } + req.SetBasicAuth(r.Username, r.Password) + req.Header.Add("Accept", ACCEPT_HEADER_V1) + + resp, err := client.Do(req) + if err != nil { + return imageTagDetail, err + } + defer resp.Body.Close() + + if resp.StatusCode != 200 { + return imageTagDetail, errors.New(fmt.Sprintf("HTTP Code: %d", resp.StatusCode)) + } + + json.NewDecoder(resp.Body).Decode(&imageTagDetail) + + return imageTagDetail, nil + +} + func (r Registry) DeleteImageByTag(image string, tag string) error { sha, err := r.getImageSHA(image, tag) if err != nil {