2015-01-14 20:02:43 +00:00
|
|
|
package storage
|
|
|
|
|
|
|
|
import (
|
|
|
|
"path"
|
|
|
|
|
2015-02-13 21:59:50 +00:00
|
|
|
"github.com/docker/distribution"
|
2015-01-14 20:02:43 +00:00
|
|
|
"github.com/docker/distribution/digest"
|
2015-02-11 02:14:23 +00:00
|
|
|
storagedriver "github.com/docker/distribution/registry/storage/driver"
|
2015-01-14 20:02:43 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// tagStore provides methods to manage manifest tags in a backend storage driver.
|
|
|
|
type tagStore struct {
|
2015-01-17 02:24:07 +00:00
|
|
|
*repository
|
2015-01-14 20:02:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// tags lists the manifest tags for the specified repository.
|
2015-01-17 02:24:07 +00:00
|
|
|
func (ts *tagStore) tags() ([]string, error) {
|
|
|
|
p, err := ts.pm.path(manifestTagPathSpec{
|
|
|
|
name: ts.name,
|
2015-01-14 20:02:43 +00:00
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var tags []string
|
|
|
|
entries, err := ts.driver.List(p)
|
|
|
|
if err != nil {
|
|
|
|
switch err := err.(type) {
|
|
|
|
case storagedriver.PathNotFoundError:
|
2015-02-13 21:59:50 +00:00
|
|
|
return nil, distribution.ErrRepositoryUnknown{Name: ts.name}
|
2015-01-14 20:02:43 +00:00
|
|
|
default:
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, entry := range entries {
|
|
|
|
_, filename := path.Split(entry)
|
|
|
|
|
|
|
|
tags = append(tags, filename)
|
|
|
|
}
|
|
|
|
|
|
|
|
return tags, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// exists returns true if the specified manifest tag exists in the repository.
|
2015-01-17 02:24:07 +00:00
|
|
|
func (ts *tagStore) exists(tag string) (bool, error) {
|
|
|
|
tagPath, err := ts.pm.path(manifestTagCurrentPathSpec{
|
|
|
|
name: ts.Name(),
|
2015-01-14 20:02:43 +00:00
|
|
|
tag: tag,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
|
|
|
|
exists, err := exists(ts.driver, tagPath)
|
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return exists, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// tag tags the digest with the given tag, updating the the store to point at
|
|
|
|
// the current tag. The digest must point to a manifest.
|
2015-01-17 02:24:07 +00:00
|
|
|
func (ts *tagStore) tag(tag string, revision digest.Digest) error {
|
2015-02-26 23:47:04 +00:00
|
|
|
indexEntryPath, err := ts.pm.path(manifestTagIndexEntryLinkPathSpec{
|
2015-01-17 02:24:07 +00:00
|
|
|
name: ts.Name(),
|
2015-01-14 20:02:43 +00:00
|
|
|
tag: tag,
|
|
|
|
revision: revision,
|
|
|
|
})
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2015-01-17 02:24:07 +00:00
|
|
|
currentPath, err := ts.pm.path(manifestTagCurrentPathSpec{
|
|
|
|
name: ts.Name(),
|
2015-01-14 20:02:43 +00:00
|
|
|
tag: tag,
|
|
|
|
})
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Link into the index
|
|
|
|
if err := ts.blobStore.link(indexEntryPath, revision); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Overwrite the current link
|
|
|
|
return ts.blobStore.link(currentPath, revision)
|
|
|
|
}
|
|
|
|
|
|
|
|
// resolve the current revision for name and tag.
|
2015-01-17 02:24:07 +00:00
|
|
|
func (ts *tagStore) resolve(tag string) (digest.Digest, error) {
|
|
|
|
currentPath, err := ts.pm.path(manifestTagCurrentPathSpec{
|
|
|
|
name: ts.Name(),
|
2015-01-14 20:02:43 +00:00
|
|
|
tag: tag,
|
|
|
|
})
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
if exists, err := exists(ts.driver, currentPath); err != nil {
|
|
|
|
return "", err
|
|
|
|
} else if !exists {
|
2015-02-13 21:59:50 +00:00
|
|
|
return "", distribution.ErrManifestUnknown{Name: ts.Name(), Tag: tag}
|
2015-01-14 20:02:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
revision, err := ts.blobStore.readlink(currentPath)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
return revision, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// revisions returns all revisions with the specified name and tag.
|
2015-01-17 02:24:07 +00:00
|
|
|
func (ts *tagStore) revisions(tag string) ([]digest.Digest, error) {
|
|
|
|
manifestTagIndexPath, err := ts.pm.path(manifestTagIndexPathSpec{
|
|
|
|
name: ts.Name(),
|
2015-01-14 20:02:43 +00:00
|
|
|
tag: tag,
|
|
|
|
})
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO(stevvooe): Need to append digest alg to get listing of revisions.
|
|
|
|
manifestTagIndexPath = path.Join(manifestTagIndexPath, "sha256")
|
|
|
|
|
|
|
|
entries, err := ts.driver.List(manifestTagIndexPath)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var revisions []digest.Digest
|
|
|
|
for _, entry := range entries {
|
|
|
|
revisions = append(revisions, digest.NewDigestFromHex("sha256", path.Base(entry)))
|
|
|
|
}
|
|
|
|
|
|
|
|
return revisions, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// delete removes the tag from repository, including the history of all
|
|
|
|
// revisions that have the specified tag.
|
2015-01-17 02:24:07 +00:00
|
|
|
func (ts *tagStore) delete(tag string) error {
|
|
|
|
tagPath, err := ts.pm.path(manifestTagPathSpec{
|
|
|
|
name: ts.Name(),
|
2015-01-14 20:02:43 +00:00
|
|
|
tag: tag,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return ts.driver.Delete(tagPath)
|
|
|
|
}
|