distribution/storage/tagstore.go
Stephen J Day ea5b999fc0 Refactor storage API to be registry oriented
In support of making the storage API ready for supporting notifications and
mirroring, we've begun the process of paring down the storage model. The
process started by creating a central Registry interface. From there, the
common name argument on the LayerService and ManifestService was factored into
a Repository interface. The rest of the changes directly follow from this.

An interface wishlist was added, suggesting a direction to take the registry
package that should support the distribution project's future goals. As these
objects move out of the storage package and we implement a Registry backed by
the http client, these design choices will start getting validation.

Signed-off-by: Stephen J Day <stephen.day@docker.com>
2015-01-16 18:33:21 -08:00

157 lines
3.3 KiB
Go

package storage
import (
"path"
"github.com/docker/distribution/digest"
"github.com/docker/distribution/storagedriver"
)
// tagStore provides methods to manage manifest tags in a backend storage driver.
type tagStore struct {
*repository
}
// tags lists the manifest tags for the specified repository.
func (ts *tagStore) tags() ([]string, error) {
p, err := ts.pm.path(manifestTagPathSpec{
name: ts.name,
})
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:
return nil, ErrUnknownRepository{Name: ts.name}
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.
func (ts *tagStore) exists(tag string) (bool, error) {
tagPath, err := ts.pm.path(manifestTagCurrentPathSpec{
name: ts.Name(),
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.
func (ts *tagStore) tag(tag string, revision digest.Digest) error {
indexEntryPath, err := ts.pm.path(manifestTagIndexEntryPathSpec{
name: ts.Name(),
tag: tag,
revision: revision,
})
if err != nil {
return err
}
currentPath, err := ts.pm.path(manifestTagCurrentPathSpec{
name: ts.Name(),
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.
func (ts *tagStore) resolve(tag string) (digest.Digest, error) {
currentPath, err := ts.pm.path(manifestTagCurrentPathSpec{
name: ts.Name(),
tag: tag,
})
if err != nil {
return "", err
}
if exists, err := exists(ts.driver, currentPath); err != nil {
return "", err
} else if !exists {
return "", ErrUnknownManifest{Name: ts.Name(), Tag: tag}
}
revision, err := ts.blobStore.readlink(currentPath)
if err != nil {
return "", err
}
return revision, nil
}
// revisions returns all revisions with the specified name and tag.
func (ts *tagStore) revisions(tag string) ([]digest.Digest, error) {
manifestTagIndexPath, err := ts.pm.path(manifestTagIndexPathSpec{
name: ts.Name(),
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.
func (ts *tagStore) delete(tag string) error {
tagPath, err := ts.pm.path(manifestTagPathSpec{
name: ts.Name(),
tag: tag,
})
if err != nil {
return err
}
return ts.driver.Delete(tagPath)
}