Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
46 changes: 46 additions & 0 deletions registry/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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 {
Expand Down