1
0
mirror of https://github.com/distribution/distribution synced 2024-11-06 19:35:52 +01:00

Remove pathMapper object

The use of the pathMapper is no longer needed the way we have organized the
code base. The extra level of indirection has proved unnecessary and confusing
so we've opted to clean it up. In the future, we may require more flexibility,
but now it is simply not required.

Signed-off-by: Stephen J Day <stephen.day@docker.com>
This commit is contained in:
Stephen J Day 2015-08-17 18:51:05 -07:00
parent 8133b04efa
commit 641cdf3ba6
15 changed files with 93 additions and 91 deletions

@ -13,7 +13,6 @@ import (
// creating and traversing backend links. // creating and traversing backend links.
type blobStore struct { type blobStore struct {
driver driver.StorageDriver driver driver.StorageDriver
pm *pathMapper
statter distribution.BlobStatter statter distribution.BlobStatter
} }
@ -94,7 +93,7 @@ func (bs *blobStore) Put(ctx context.Context, mediaType string, p []byte) (distr
// path returns the canonical path for the blob identified by digest. The blob // path returns the canonical path for the blob identified by digest. The blob
// may or may not exist. // may or may not exist.
func (bs *blobStore) path(dgst digest.Digest) (string, error) { func (bs *blobStore) path(dgst digest.Digest) (string, error) {
bp, err := bs.pm.path(blobDataPathSpec{ bp, err := pathFor(blobDataPathSpec{
digest: dgst, digest: dgst,
}) })
@ -140,7 +139,6 @@ func (bs *blobStore) resolve(ctx context.Context, path string) (string, error) {
type blobStatter struct { type blobStatter struct {
driver driver.StorageDriver driver driver.StorageDriver
pm *pathMapper
} }
var _ distribution.BlobDescriptorService = &blobStatter{} var _ distribution.BlobDescriptorService = &blobStatter{}
@ -149,9 +147,10 @@ var _ distribution.BlobDescriptorService = &blobStatter{}
// in the main blob store. If this method returns successfully, there is // in the main blob store. If this method returns successfully, there is
// strong guarantee that the blob exists and is available. // strong guarantee that the blob exists and is available.
func (bs *blobStatter) Stat(ctx context.Context, dgst digest.Digest) (distribution.Descriptor, error) { func (bs *blobStatter) Stat(ctx context.Context, dgst digest.Digest) (distribution.Descriptor, error) {
path, err := bs.pm.path(blobDataPathSpec{ path, err := pathFor(blobDataPathSpec{
digest: dgst, digest: dgst,
}) })
if err != nil { if err != nil {
return distribution.Descriptor{}, err return distribution.Descriptor{}, err
} }

@ -266,7 +266,7 @@ func (bw *blobWriter) validateBlob(ctx context.Context, desc distribution.Descri
// identified by dgst. The layer should be validated before commencing the // identified by dgst. The layer should be validated before commencing the
// move. // move.
func (bw *blobWriter) moveBlob(ctx context.Context, desc distribution.Descriptor) error { func (bw *blobWriter) moveBlob(ctx context.Context, desc distribution.Descriptor) error {
blobPath, err := bw.blobStore.pm.path(blobDataPathSpec{ blobPath, err := pathFor(blobDataPathSpec{
digest: desc.Digest, digest: desc.Digest,
}) })
@ -324,7 +324,7 @@ func (bw *blobWriter) moveBlob(ctx context.Context, desc distribution.Descriptor
// instance. An error will be returned if the clean up cannot proceed. If the // instance. An error will be returned if the clean up cannot proceed. If the
// resources are already not present, no error will be returned. // resources are already not present, no error will be returned.
func (bw *blobWriter) removeResources(ctx context.Context) error { func (bw *blobWriter) removeResources(ctx context.Context) error {
dataPath, err := bw.blobStore.pm.path(uploadDataPathSpec{ dataPath, err := pathFor(uploadDataPathSpec{
name: bw.blobStore.repository.Name(), name: bw.blobStore.repository.Name(),
id: bw.id, id: bw.id,
}) })

@ -111,12 +111,13 @@ type hashStateEntry struct {
// getStoredHashStates returns a slice of hashStateEntries for this upload. // getStoredHashStates returns a slice of hashStateEntries for this upload.
func (bw *blobWriter) getStoredHashStates(ctx context.Context) ([]hashStateEntry, error) { func (bw *blobWriter) getStoredHashStates(ctx context.Context) ([]hashStateEntry, error) {
uploadHashStatePathPrefix, err := bw.blobStore.pm.path(uploadHashStatePathSpec{ uploadHashStatePathPrefix, err := pathFor(uploadHashStatePathSpec{
name: bw.blobStore.repository.Name(), name: bw.blobStore.repository.Name(),
id: bw.id, id: bw.id,
alg: bw.digester.Digest().Algorithm(), alg: bw.digester.Digest().Algorithm(),
list: true, list: true,
}) })
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -156,12 +157,13 @@ func (bw *blobWriter) storeHashState(ctx context.Context) error {
return errResumableDigestNotAvailable return errResumableDigestNotAvailable
} }
uploadHashStatePath, err := bw.blobStore.pm.path(uploadHashStatePathSpec{ uploadHashStatePath, err := pathFor(uploadHashStatePathSpec{
name: bw.blobStore.repository.Name(), name: bw.blobStore.repository.Name(),
id: bw.id, id: bw.id,
alg: bw.digester.Digest().Algorithm(), alg: bw.digester.Digest().Algorithm(),
offset: int64(h.Len()), offset: int64(h.Len()),
}) })
if err != nil { if err != nil {
return err return err
} }

@ -22,7 +22,7 @@ func (reg *registry) Repositories(ctx context.Context, repos []string, last stri
return 0, errors.New("no space in slice") return 0, errors.New("no space in slice")
} }
root, err := defaultPathMapper.path(repositoriesRootPathSpec{}) root, err := pathFor(repositoriesRootPathSpec{})
if err != nil { if err != nil {
return 0, err return 0, err
} }

@ -23,7 +23,7 @@ func setupFS(t *testing.T) *setupEnv {
c := []byte("") c := []byte("")
ctx := context.Background() ctx := context.Background()
registry := NewRegistryWithDriver(ctx, d, memory.NewInMemoryBlobDescriptorCacheProvider(), false, true, false) registry := NewRegistryWithDriver(ctx, d, memory.NewInMemoryBlobDescriptorCacheProvider(), false, true, false)
rootpath, _ := defaultPathMapper.path(repositoriesRootPathSpec{}) rootpath, _ := pathFor(repositoriesRootPathSpec{})
repos := []string{ repos := []string{
"/foo/a/_layers/1", "/foo/a/_layers/1",

@ -13,7 +13,7 @@ import (
// linkPathFunc describes a function that can resolve a link based on the // linkPathFunc describes a function that can resolve a link based on the
// repository name and digest. // repository name and digest.
type linkPathFunc func(pm *pathMapper, name string, dgst digest.Digest) (string, error) type linkPathFunc func(name string, dgst digest.Digest) (string, error)
// linkedBlobStore provides a full BlobService that namespaces the blobs to a // linkedBlobStore provides a full BlobService that namespaces the blobs to a
// given repository. Effectively, it manages the links in a given repository // given repository. Effectively, it manages the links in a given repository
@ -104,7 +104,7 @@ func (lbs *linkedBlobStore) Create(ctx context.Context) (distribution.BlobWriter
uuid := uuid.Generate().String() uuid := uuid.Generate().String()
startedAt := time.Now().UTC() startedAt := time.Now().UTC()
path, err := lbs.blobStore.pm.path(uploadDataPathSpec{ path, err := pathFor(uploadDataPathSpec{
name: lbs.repository.Name(), name: lbs.repository.Name(),
id: uuid, id: uuid,
}) })
@ -113,7 +113,7 @@ func (lbs *linkedBlobStore) Create(ctx context.Context) (distribution.BlobWriter
return nil, err return nil, err
} }
startedAtPath, err := lbs.blobStore.pm.path(uploadStartedAtPathSpec{ startedAtPath, err := pathFor(uploadStartedAtPathSpec{
name: lbs.repository.Name(), name: lbs.repository.Name(),
id: uuid, id: uuid,
}) })
@ -133,7 +133,7 @@ func (lbs *linkedBlobStore) Create(ctx context.Context) (distribution.BlobWriter
func (lbs *linkedBlobStore) Resume(ctx context.Context, id string) (distribution.BlobWriter, error) { func (lbs *linkedBlobStore) Resume(ctx context.Context, id string) (distribution.BlobWriter, error) {
context.GetLogger(ctx).Debug("(*linkedBlobStore).Resume") context.GetLogger(ctx).Debug("(*linkedBlobStore).Resume")
startedAtPath, err := lbs.blobStore.pm.path(uploadStartedAtPathSpec{ startedAtPath, err := pathFor(uploadStartedAtPathSpec{
name: lbs.repository.Name(), name: lbs.repository.Name(),
id: id, id: id,
}) })
@ -157,7 +157,7 @@ func (lbs *linkedBlobStore) Resume(ctx context.Context, id string) (distribution
return nil, err return nil, err
} }
path, err := lbs.pm.path(uploadDataPathSpec{ path, err := pathFor(uploadDataPathSpec{
name: lbs.repository.Name(), name: lbs.repository.Name(),
id: id, id: id,
}) })
@ -228,7 +228,7 @@ func (lbs *linkedBlobStore) linkBlob(ctx context.Context, canonical distribution
} }
seenDigests[dgst] = struct{}{} seenDigests[dgst] = struct{}{}
blobLinkPath, err := linkPathFn(lbs.pm, lbs.repository.Name(), dgst) blobLinkPath, err := linkPathFn(lbs.repository.Name(), dgst)
if err != nil { if err != nil {
return err return err
} }
@ -298,7 +298,7 @@ func (lbs *linkedBlobStatter) Stat(ctx context.Context, dgst digest.Digest) (dis
func (lbs *linkedBlobStatter) Clear(ctx context.Context, dgst digest.Digest) (err error) { func (lbs *linkedBlobStatter) Clear(ctx context.Context, dgst digest.Digest) (err error) {
// clear any possible existence of a link described in linkPathFns // clear any possible existence of a link described in linkPathFns
for _, linkPathFn := range lbs.linkPathFns { for _, linkPathFn := range lbs.linkPathFns {
blobLinkPath, err := linkPathFn(lbs.pm, lbs.repository.Name(), dgst) blobLinkPath, err := linkPathFn(lbs.repository.Name(), dgst)
if err != nil { if err != nil {
return err return err
} }
@ -321,7 +321,7 @@ func (lbs *linkedBlobStatter) Clear(ctx context.Context, dgst digest.Digest) (er
// linkPathFuncs to let us try a few different paths before returning not // linkPathFuncs to let us try a few different paths before returning not
// found. // found.
func (lbs *linkedBlobStatter) resolveWithLinkFunc(ctx context.Context, dgst digest.Digest, linkPathFn linkPathFunc) (digest.Digest, error) { func (lbs *linkedBlobStatter) resolveWithLinkFunc(ctx context.Context, dgst digest.Digest, linkPathFn linkPathFunc) (digest.Digest, error) {
blobLinkPath, err := linkPathFn(lbs.pm, lbs.repository.Name(), dgst) blobLinkPath, err := linkPathFn(lbs.repository.Name(), dgst)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -335,11 +335,11 @@ func (lbs *linkedBlobStatter) SetDescriptor(ctx context.Context, dgst digest.Dig
} }
// blobLinkPath provides the path to the blob link, also known as layers. // blobLinkPath provides the path to the blob link, also known as layers.
func blobLinkPath(pm *pathMapper, name string, dgst digest.Digest) (string, error) { func blobLinkPath(name string, dgst digest.Digest) (string, error) {
return pm.path(layerLinkPathSpec{name: name, digest: dgst}) return pathFor(layerLinkPathSpec{name: name, digest: dgst})
} }
// manifestRevisionLinkPath provides the path to the manifest revision link. // manifestRevisionLinkPath provides the path to the manifest revision link.
func manifestRevisionLinkPath(pm *pathMapper, name string, dgst digest.Digest) (string, error) { func manifestRevisionLinkPath(name string, dgst digest.Digest) (string, error) {
return pm.path(manifestRevisionLinkPathSpec{name: name, revision: dgst}) return pathFor(manifestRevisionLinkPathSpec{name: name, revision: dgst})
} }

@ -385,7 +385,7 @@ func TestLinkPathFuncs(t *testing.T) {
expected: "/docker/registry/v2/repositories/foo/bar/_manifests/revisions/sha256/deadbeaf/link", expected: "/docker/registry/v2/repositories/foo/bar/_manifests/revisions/sha256/deadbeaf/link",
}, },
} { } {
p, err := testcase.linkPathFn(defaultPathMapper, testcase.repo, testcase.digest) p, err := testcase.linkPathFn(testcase.repo, testcase.digest)
if err != nil { if err != nil {
t.Fatalf("unexpected error calling linkPathFn(pm, %q, %q): %v", testcase.repo, testcase.digest, err) t.Fatalf("unexpected error calling linkPathFn(pm, %q, %q): %v", testcase.repo, testcase.digest, err)
} }

@ -8,10 +8,18 @@ import (
"github.com/docker/distribution/digest" "github.com/docker/distribution/digest"
) )
const storagePathVersion = "v2" const (
storagePathVersion = "v2" // fixed storage layout version
storagePathRoot = "/docker/registry/" // all driver paths have a prefix
// pathMapper maps paths based on "object names" and their ids. The "object // TODO(stevvooe): Get rid of the "storagePathRoot". Initially, we though
// names" mapped by pathMapper are internal to the storage system. // storage path root would configurable for all drivers through this
// package. In reality, we've found it simpler to do this on a per driver
// basis.
)
// pathFor maps paths based on "object names" and their ids. The "object
// names" mapped by are internal to the storage system.
// //
// The path layout in the storage backend is roughly as follows: // The path layout in the storage backend is roughly as follows:
// //
@ -37,7 +45,7 @@ const storagePathVersion = "v2"
// -> blob/<algorithm> // -> blob/<algorithm>
// <split directory content addressable storage> // <split directory content addressable storage>
// //
// The storage backend layout is broken up into a content- addressable blob // The storage backend layout is broken up into a content-addressable blob
// store and repositories. The content-addressable blob store holds most data // store and repositories. The content-addressable blob store holds most data
// throughout the backend, keyed by algorithm and digests of the underlying // throughout the backend, keyed by algorithm and digests of the underlying
// content. Access to the blob store is controled through links from the // content. Access to the blob store is controled through links from the
@ -98,18 +106,7 @@ const storagePathVersion = "v2"
// //
// For more information on the semantic meaning of each path and their // For more information on the semantic meaning of each path and their
// contents, please see the path spec documentation. // contents, please see the path spec documentation.
type pathMapper struct { func pathFor(spec pathSpec) (string, error) {
root string
version string // should be a constant?
}
var defaultPathMapper = &pathMapper{
root: "/docker/registry/",
version: storagePathVersion,
}
// path returns the path identified by spec.
func (pm *pathMapper) path(spec pathSpec) (string, error) {
// Switch on the path object type and return the appropriate path. At // Switch on the path object type and return the appropriate path. At
// first glance, one may wonder why we don't use an interface to // first glance, one may wonder why we don't use an interface to
@ -123,7 +120,7 @@ func (pm *pathMapper) path(spec pathSpec) (string, error) {
// to an intermediate path object, than can be consumed and mapped by the // to an intermediate path object, than can be consumed and mapped by the
// other version. // other version.
rootPrefix := []string{pm.root, pm.version} rootPrefix := []string{storagePathRoot, storagePathVersion}
repoPrefix := append(rootPrefix, "repositories") repoPrefix := append(rootPrefix, "repositories")
switch v := spec.(type) { switch v := spec.(type) {
@ -136,7 +133,7 @@ func (pm *pathMapper) path(spec pathSpec) (string, error) {
return path.Join(append(append(repoPrefix, v.name, "_manifests", "revisions"), components...)...), nil return path.Join(append(append(repoPrefix, v.name, "_manifests", "revisions"), components...)...), nil
case manifestRevisionLinkPathSpec: case manifestRevisionLinkPathSpec:
root, err := pm.path(manifestRevisionPathSpec{ root, err := pathFor(manifestRevisionPathSpec{
name: v.name, name: v.name,
revision: v.revision, revision: v.revision,
}) })
@ -147,7 +144,7 @@ func (pm *pathMapper) path(spec pathSpec) (string, error) {
return path.Join(root, "link"), nil return path.Join(root, "link"), nil
case manifestSignaturesPathSpec: case manifestSignaturesPathSpec:
root, err := pm.path(manifestRevisionPathSpec{ root, err := pathFor(manifestRevisionPathSpec{
name: v.name, name: v.name,
revision: v.revision, revision: v.revision,
}) })
@ -158,10 +155,11 @@ func (pm *pathMapper) path(spec pathSpec) (string, error) {
return path.Join(root, "signatures"), nil return path.Join(root, "signatures"), nil
case manifestSignatureLinkPathSpec: case manifestSignatureLinkPathSpec:
root, err := pm.path(manifestSignaturesPathSpec{ root, err := pathFor(manifestSignaturesPathSpec{
name: v.name, name: v.name,
revision: v.revision, revision: v.revision,
}) })
if err != nil { if err != nil {
return "", err return "", err
} }
@ -175,50 +173,55 @@ func (pm *pathMapper) path(spec pathSpec) (string, error) {
case manifestTagsPathSpec: case manifestTagsPathSpec:
return path.Join(append(repoPrefix, v.name, "_manifests", "tags")...), nil return path.Join(append(repoPrefix, v.name, "_manifests", "tags")...), nil
case manifestTagPathSpec: case manifestTagPathSpec:
root, err := pm.path(manifestTagsPathSpec{ root, err := pathFor(manifestTagsPathSpec{
name: v.name, name: v.name,
}) })
if err != nil { if err != nil {
return "", err return "", err
} }
return path.Join(root, v.tag), nil return path.Join(root, v.tag), nil
case manifestTagCurrentPathSpec: case manifestTagCurrentPathSpec:
root, err := pm.path(manifestTagPathSpec{ root, err := pathFor(manifestTagPathSpec{
name: v.name, name: v.name,
tag: v.tag, tag: v.tag,
}) })
if err != nil { if err != nil {
return "", err return "", err
} }
return path.Join(root, "current", "link"), nil return path.Join(root, "current", "link"), nil
case manifestTagIndexPathSpec: case manifestTagIndexPathSpec:
root, err := pm.path(manifestTagPathSpec{ root, err := pathFor(manifestTagPathSpec{
name: v.name, name: v.name,
tag: v.tag, tag: v.tag,
}) })
if err != nil { if err != nil {
return "", err return "", err
} }
return path.Join(root, "index"), nil return path.Join(root, "index"), nil
case manifestTagIndexEntryLinkPathSpec: case manifestTagIndexEntryLinkPathSpec:
root, err := pm.path(manifestTagIndexEntryPathSpec{ root, err := pathFor(manifestTagIndexEntryPathSpec{
name: v.name, name: v.name,
tag: v.tag, tag: v.tag,
revision: v.revision, revision: v.revision,
}) })
if err != nil { if err != nil {
return "", err return "", err
} }
return path.Join(root, "link"), nil return path.Join(root, "link"), nil
case manifestTagIndexEntryPathSpec: case manifestTagIndexEntryPathSpec:
root, err := pm.path(manifestTagIndexPathSpec{ root, err := pathFor(manifestTagIndexPathSpec{
name: v.name, name: v.name,
tag: v.tag, tag: v.tag,
}) })
if err != nil { if err != nil {
return "", err return "", err
} }

@ -7,10 +7,6 @@ import (
) )
func TestPathMapper(t *testing.T) { func TestPathMapper(t *testing.T) {
pm := &pathMapper{
root: "/pathmapper-test",
}
for _, testcase := range []struct { for _, testcase := range []struct {
spec pathSpec spec pathSpec
expected string expected string
@ -21,14 +17,14 @@ func TestPathMapper(t *testing.T) {
name: "foo/bar", name: "foo/bar",
revision: "sha256:abcdef0123456789", revision: "sha256:abcdef0123456789",
}, },
expected: "/pathmapper-test/repositories/foo/bar/_manifests/revisions/sha256/abcdef0123456789", expected: "/docker/registry/v2/repositories/foo/bar/_manifests/revisions/sha256/abcdef0123456789",
}, },
{ {
spec: manifestRevisionLinkPathSpec{ spec: manifestRevisionLinkPathSpec{
name: "foo/bar", name: "foo/bar",
revision: "sha256:abcdef0123456789", revision: "sha256:abcdef0123456789",
}, },
expected: "/pathmapper-test/repositories/foo/bar/_manifests/revisions/sha256/abcdef0123456789/link", expected: "/docker/registry/v2/repositories/foo/bar/_manifests/revisions/sha256/abcdef0123456789/link",
}, },
{ {
spec: manifestSignatureLinkPathSpec{ spec: manifestSignatureLinkPathSpec{
@ -36,41 +32,41 @@ func TestPathMapper(t *testing.T) {
revision: "sha256:abcdef0123456789", revision: "sha256:abcdef0123456789",
signature: "sha256:abcdef0123456789", signature: "sha256:abcdef0123456789",
}, },
expected: "/pathmapper-test/repositories/foo/bar/_manifests/revisions/sha256/abcdef0123456789/signatures/sha256/abcdef0123456789/link", expected: "/docker/registry/v2/repositories/foo/bar/_manifests/revisions/sha256/abcdef0123456789/signatures/sha256/abcdef0123456789/link",
}, },
{ {
spec: manifestSignaturesPathSpec{ spec: manifestSignaturesPathSpec{
name: "foo/bar", name: "foo/bar",
revision: "sha256:abcdef0123456789", revision: "sha256:abcdef0123456789",
}, },
expected: "/pathmapper-test/repositories/foo/bar/_manifests/revisions/sha256/abcdef0123456789/signatures", expected: "/docker/registry/v2/repositories/foo/bar/_manifests/revisions/sha256/abcdef0123456789/signatures",
}, },
{ {
spec: manifestTagsPathSpec{ spec: manifestTagsPathSpec{
name: "foo/bar", name: "foo/bar",
}, },
expected: "/pathmapper-test/repositories/foo/bar/_manifests/tags", expected: "/docker/registry/v2/repositories/foo/bar/_manifests/tags",
}, },
{ {
spec: manifestTagPathSpec{ spec: manifestTagPathSpec{
name: "foo/bar", name: "foo/bar",
tag: "thetag", tag: "thetag",
}, },
expected: "/pathmapper-test/repositories/foo/bar/_manifests/tags/thetag", expected: "/docker/registry/v2/repositories/foo/bar/_manifests/tags/thetag",
}, },
{ {
spec: manifestTagCurrentPathSpec{ spec: manifestTagCurrentPathSpec{
name: "foo/bar", name: "foo/bar",
tag: "thetag", tag: "thetag",
}, },
expected: "/pathmapper-test/repositories/foo/bar/_manifests/tags/thetag/current/link", expected: "/docker/registry/v2/repositories/foo/bar/_manifests/tags/thetag/current/link",
}, },
{ {
spec: manifestTagIndexPathSpec{ spec: manifestTagIndexPathSpec{
name: "foo/bar", name: "foo/bar",
tag: "thetag", tag: "thetag",
}, },
expected: "/pathmapper-test/repositories/foo/bar/_manifests/tags/thetag/index", expected: "/docker/registry/v2/repositories/foo/bar/_manifests/tags/thetag/index",
}, },
{ {
spec: manifestTagIndexEntryPathSpec{ spec: manifestTagIndexEntryPathSpec{
@ -78,7 +74,7 @@ func TestPathMapper(t *testing.T) {
tag: "thetag", tag: "thetag",
revision: "sha256:abcdef0123456789", revision: "sha256:abcdef0123456789",
}, },
expected: "/pathmapper-test/repositories/foo/bar/_manifests/tags/thetag/index/sha256/abcdef0123456789", expected: "/docker/registry/v2/repositories/foo/bar/_manifests/tags/thetag/index/sha256/abcdef0123456789",
}, },
{ {
spec: manifestTagIndexEntryLinkPathSpec{ spec: manifestTagIndexEntryLinkPathSpec{
@ -86,26 +82,26 @@ func TestPathMapper(t *testing.T) {
tag: "thetag", tag: "thetag",
revision: "sha256:abcdef0123456789", revision: "sha256:abcdef0123456789",
}, },
expected: "/pathmapper-test/repositories/foo/bar/_manifests/tags/thetag/index/sha256/abcdef0123456789/link", expected: "/docker/registry/v2/repositories/foo/bar/_manifests/tags/thetag/index/sha256/abcdef0123456789/link",
}, },
{ {
spec: layerLinkPathSpec{ spec: layerLinkPathSpec{
name: "foo/bar", name: "foo/bar",
digest: "tarsum.v1+test:abcdef", digest: "tarsum.v1+test:abcdef",
}, },
expected: "/pathmapper-test/repositories/foo/bar/_layers/tarsum/v1/test/abcdef/link", expected: "/docker/registry/v2/repositories/foo/bar/_layers/tarsum/v1/test/abcdef/link",
}, },
{ {
spec: blobDataPathSpec{ spec: blobDataPathSpec{
digest: digest.Digest("tarsum.dev+sha512:abcdefabcdefabcdef908909909"), digest: digest.Digest("tarsum.dev+sha512:abcdefabcdefabcdef908909909"),
}, },
expected: "/pathmapper-test/blobs/tarsum/dev/sha512/ab/abcdefabcdefabcdef908909909/data", expected: "/docker/registry/v2/blobs/tarsum/dev/sha512/ab/abcdefabcdefabcdef908909909/data",
}, },
{ {
spec: blobDataPathSpec{ spec: blobDataPathSpec{
digest: digest.Digest("tarsum.v1+sha256:abcdefabcdefabcdef908909909"), digest: digest.Digest("tarsum.v1+sha256:abcdefabcdefabcdef908909909"),
}, },
expected: "/pathmapper-test/blobs/tarsum/v1/sha256/ab/abcdefabcdefabcdef908909909/data", expected: "/docker/registry/v2/blobs/tarsum/v1/sha256/ab/abcdefabcdefabcdef908909909/data",
}, },
{ {
@ -113,17 +109,17 @@ func TestPathMapper(t *testing.T) {
name: "foo/bar", name: "foo/bar",
id: "asdf-asdf-asdf-adsf", id: "asdf-asdf-asdf-adsf",
}, },
expected: "/pathmapper-test/repositories/foo/bar/_uploads/asdf-asdf-asdf-adsf/data", expected: "/docker/registry/v2/repositories/foo/bar/_uploads/asdf-asdf-asdf-adsf/data",
}, },
{ {
spec: uploadStartedAtPathSpec{ spec: uploadStartedAtPathSpec{
name: "foo/bar", name: "foo/bar",
id: "asdf-asdf-asdf-adsf", id: "asdf-asdf-asdf-adsf",
}, },
expected: "/pathmapper-test/repositories/foo/bar/_uploads/asdf-asdf-asdf-adsf/startedat", expected: "/docker/registry/v2/repositories/foo/bar/_uploads/asdf-asdf-asdf-adsf/startedat",
}, },
} { } {
p, err := pm.path(testcase.spec) p, err := pathFor(testcase.spec)
if err != nil { if err != nil {
t.Fatalf("unexpected generating path (%T): %v", testcase.spec, err) t.Fatalf("unexpected generating path (%T): %v", testcase.spec, err)
} }
@ -136,9 +132,10 @@ func TestPathMapper(t *testing.T) {
// Add a few test cases to ensure we cover some errors // Add a few test cases to ensure we cover some errors
// Specify a path that requires a revision and get a digest validation error. // Specify a path that requires a revision and get a digest validation error.
badpath, err := pm.path(manifestSignaturesPathSpec{ badpath, err := pathFor(manifestSignaturesPathSpec{
name: "foo/bar", name: "foo/bar",
}) })
if err == nil { if err == nil {
t.Fatalf("expected an error when mapping an invalid revision: %s", badpath) t.Fatalf("expected an error when mapping an invalid revision: %s", badpath)
} }

@ -62,10 +62,11 @@ func getOutstandingUploads(ctx context.Context, driver storageDriver.StorageDriv
uploads := make(map[string]uploadData, 0) uploads := make(map[string]uploadData, 0)
inUploadDir := false inUploadDir := false
root, err := defaultPathMapper.path(repositoriesRootPathSpec{}) root, err := pathFor(repositoriesRootPathSpec{})
if err != nil { if err != nil {
return uploads, append(errors, err) return uploads, append(errors, err)
} }
err = Walk(ctx, driver, root, func(fileInfo storageDriver.FileInfo) error { err = Walk(ctx, driver, root, func(fileInfo storageDriver.FileInfo) error {
filePath := fileInfo.Path() filePath := fileInfo.Path()
_, file := path.Split(filePath) _, file := path.Split(filePath)

@ -12,8 +12,6 @@ import (
"github.com/docker/distribution/uuid" "github.com/docker/distribution/uuid"
) )
var pm = defaultPathMapper
func testUploadFS(t *testing.T, numUploads int, repoName string, startedAt time.Time) (driver.StorageDriver, context.Context) { func testUploadFS(t *testing.T, numUploads int, repoName string, startedAt time.Time) (driver.StorageDriver, context.Context) {
d := inmemory.New() d := inmemory.New()
ctx := context.Background() ctx := context.Background()
@ -24,7 +22,7 @@ func testUploadFS(t *testing.T, numUploads int, repoName string, startedAt time.
} }
func addUploads(ctx context.Context, t *testing.T, d driver.StorageDriver, uploadID, repo string, startedAt time.Time) { func addUploads(ctx context.Context, t *testing.T, d driver.StorageDriver, uploadID, repo string, startedAt time.Time) {
dataPath, err := pm.path(uploadDataPathSpec{name: repo, id: uploadID}) dataPath, err := pathFor(uploadDataPathSpec{name: repo, id: uploadID})
if err != nil { if err != nil {
t.Fatalf("Unable to resolve path") t.Fatalf("Unable to resolve path")
} }
@ -32,7 +30,7 @@ func addUploads(ctx context.Context, t *testing.T, d driver.StorageDriver, uploa
t.Fatalf("Unable to write data file") t.Fatalf("Unable to write data file")
} }
startedAtPath, err := pm.path(uploadStartedAtPathSpec{name: repo, id: uploadID}) startedAtPath, err := pathFor(uploadStartedAtPathSpec{name: repo, id: uploadID})
if err != nil { if err != nil {
t.Fatalf("Unable to resolve path") t.Fatalf("Unable to resolve path")
} }
@ -115,7 +113,7 @@ func TestPurgeOnlyUploads(t *testing.T) {
// Create a directory tree outside _uploads and ensure // Create a directory tree outside _uploads and ensure
// these files aren't deleted. // these files aren't deleted.
dataPath, err := pm.path(uploadDataPathSpec{name: "test-repo", id: uuid.Generate().String()}) dataPath, err := pathFor(uploadDataPathSpec{name: "test-repo", id: uuid.Generate().String()})
if err != nil { if err != nil {
t.Fatalf(err.Error()) t.Fatalf(err.Error())
} }

@ -30,7 +30,6 @@ func NewRegistryWithDriver(ctx context.Context, driver storagedriver.StorageDriv
// create global statter, with cache. // create global statter, with cache.
var statter distribution.BlobDescriptorService = &blobStatter{ var statter distribution.BlobDescriptorService = &blobStatter{
driver: driver, driver: driver,
pm: defaultPathMapper,
} }
if blobDescriptorCacheProvider != nil { if blobDescriptorCacheProvider != nil {
@ -39,7 +38,6 @@ func NewRegistryWithDriver(ctx context.Context, driver storagedriver.StorageDriv
bs := &blobStore{ bs := &blobStore{
driver: driver, driver: driver,
pm: defaultPathMapper,
statter: statter, statter: statter,
} }

@ -26,7 +26,7 @@ func newSignatureStore(ctx context.Context, repo *repository, blobStore *blobSto
var _ distribution.SignatureService = &signatureStore{} var _ distribution.SignatureService = &signatureStore{}
func (s *signatureStore) Get(dgst digest.Digest) ([][]byte, error) { func (s *signatureStore) Get(dgst digest.Digest) ([][]byte, error) {
signaturesPath, err := s.blobStore.pm.path(manifestSignaturesPathSpec{ signaturesPath, err := pathFor(manifestSignaturesPathSpec{
name: s.repository.Name(), name: s.repository.Name(),
revision: dgst, revision: dgst,
}) })
@ -119,12 +119,13 @@ func (s *signatureStore) Put(dgst digest.Digest, signatures ...[]byte) error {
// manifest with the given digest. Effectively, each signature link path // manifest with the given digest. Effectively, each signature link path
// layout is a unique linked blob store. // layout is a unique linked blob store.
func (s *signatureStore) linkedBlobStore(ctx context.Context, revision digest.Digest) *linkedBlobStore { func (s *signatureStore) linkedBlobStore(ctx context.Context, revision digest.Digest) *linkedBlobStore {
linkpath := func(pm *pathMapper, name string, dgst digest.Digest) (string, error) { linkpath := func(name string, dgst digest.Digest) (string, error) {
return pm.path(manifestSignatureLinkPathSpec{ return pathFor(manifestSignatureLinkPathSpec{
name: name, name: name,
revision: revision, revision: revision,
signature: dgst, signature: dgst,
}) })
} }
return &linkedBlobStore{ return &linkedBlobStore{

@ -18,9 +18,10 @@ type tagStore struct {
// tags lists the manifest tags for the specified repository. // tags lists the manifest tags for the specified repository.
func (ts *tagStore) tags() ([]string, error) { func (ts *tagStore) tags() ([]string, error) {
p, err := ts.blobStore.pm.path(manifestTagPathSpec{ p, err := pathFor(manifestTagPathSpec{
name: ts.repository.Name(), name: ts.repository.Name(),
}) })
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -47,10 +48,11 @@ func (ts *tagStore) tags() ([]string, error) {
// exists returns true if the specified manifest tag exists in the repository. // exists returns true if the specified manifest tag exists in the repository.
func (ts *tagStore) exists(tag string) (bool, error) { func (ts *tagStore) exists(tag string) (bool, error) {
tagPath, err := ts.blobStore.pm.path(manifestTagCurrentPathSpec{ tagPath, err := pathFor(manifestTagCurrentPathSpec{
name: ts.repository.Name(), name: ts.repository.Name(),
tag: tag, tag: tag,
}) })
if err != nil { if err != nil {
return false, err return false, err
} }
@ -66,7 +68,7 @@ func (ts *tagStore) exists(tag string) (bool, error) {
// tag tags the digest with the given tag, updating the the store to point at // 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. // the current tag. The digest must point to a manifest.
func (ts *tagStore) tag(tag string, revision digest.Digest) error { func (ts *tagStore) tag(tag string, revision digest.Digest) error {
currentPath, err := ts.blobStore.pm.path(manifestTagCurrentPathSpec{ currentPath, err := pathFor(manifestTagCurrentPathSpec{
name: ts.repository.Name(), name: ts.repository.Name(),
tag: tag, tag: tag,
}) })
@ -87,10 +89,11 @@ func (ts *tagStore) tag(tag string, revision digest.Digest) error {
// resolve the current revision for name and tag. // resolve the current revision for name and tag.
func (ts *tagStore) resolve(tag string) (digest.Digest, error) { func (ts *tagStore) resolve(tag string) (digest.Digest, error) {
currentPath, err := ts.blobStore.pm.path(manifestTagCurrentPathSpec{ currentPath, err := pathFor(manifestTagCurrentPathSpec{
name: ts.repository.Name(), name: ts.repository.Name(),
tag: tag, tag: tag,
}) })
if err != nil { if err != nil {
return "", err return "", err
} }
@ -111,10 +114,11 @@ func (ts *tagStore) resolve(tag string) (digest.Digest, error) {
// delete removes the tag from repository, including the history of all // delete removes the tag from repository, including the history of all
// revisions that have the specified tag. // revisions that have the specified tag.
func (ts *tagStore) delete(tag string) error { func (ts *tagStore) delete(tag string) error {
tagPath, err := ts.blobStore.pm.path(manifestTagPathSpec{ tagPath, err := pathFor(manifestTagPathSpec{
name: ts.repository.Name(), name: ts.repository.Name(),
tag: tag, tag: tag,
}) })
if err != nil { if err != nil {
return err return err
} }
@ -131,12 +135,13 @@ func (ts *tagStore) linkedBlobStore(ctx context.Context, tag string) *linkedBlob
blobStore: ts.blobStore, blobStore: ts.blobStore,
repository: ts.repository, repository: ts.repository,
ctx: ctx, ctx: ctx,
linkPathFns: []linkPathFunc{func(pm *pathMapper, name string, dgst digest.Digest) (string, error) { linkPathFns: []linkPathFunc{func(name string, dgst digest.Digest) (string, error) {
return pm.path(manifestTagIndexEntryLinkPathSpec{ return pathFor(manifestTagIndexEntryLinkPathSpec{
name: name, name: name,
tag: tag, tag: tag,
revision: dgst, revision: dgst,
}) })
}}, }},
} }
} }

@ -18,13 +18,11 @@ func NewVacuum(ctx context.Context, driver driver.StorageDriver) Vacuum {
return Vacuum{ return Vacuum{
ctx: ctx, ctx: ctx,
driver: driver, driver: driver,
pm: defaultPathMapper,
} }
} }
// Vacuum removes content from the filesystem // Vacuum removes content from the filesystem
type Vacuum struct { type Vacuum struct {
pm *pathMapper
driver driver.StorageDriver driver driver.StorageDriver
ctx context.Context ctx context.Context
} }
@ -36,7 +34,7 @@ func (v Vacuum) RemoveBlob(dgst string) error {
return err return err
} }
blobPath, err := v.pm.path(blobDataPathSpec{digest: d}) blobPath, err := pathFor(blobDataPathSpec{digest: d})
if err != nil { if err != nil {
return err return err
} }
@ -52,7 +50,7 @@ func (v Vacuum) RemoveBlob(dgst string) error {
// RemoveRepository removes a repository directory from the // RemoveRepository removes a repository directory from the
// filesystem // filesystem
func (v Vacuum) RemoveRepository(repoName string) error { func (v Vacuum) RemoveRepository(repoName string) error {
rootForRepository, err := v.pm.path(repositoriesRootPathSpec{}) rootForRepository, err := pathFor(repositoriesRootPathSpec{})
if err != nil { if err != nil {
return err return err
} }