8000 Manifest interface refactor by RichardScothern · Pull Request #1105 · distribution/distribution · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Manifest interface refactor #1105

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
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
64 changes: 64 additions & 0 deletions manifests.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package distribution

import (
"github.com/docker/distribution/context"
"github.com/docker/distribution/digest"
"github.com/docker/distribution/reference"
)

// Manifest represents a registry object specifying a set of
// references and an optional target
type Manifest interface {
// Target returns a descriptor for the configuration of this manifest. This
// may return a nil descriptor if a target is not applicable for the given manifest.
Target() Descriptor
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this return nil for old-style manifests? If so, shouldn't it be part of a more specific interface?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did consider this, but didn't want to fragment the interface.

Perhaps more explicit return types (e.g. returning ErrNotSupported) would work here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm... I don't want to make a big deal out of it, but it doesn't seem right to me to have a method in an interface that's specific to one of the implementations. What do others think?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The target should just be the manifest itself.


// References returns a list of objects which make up this manifest.
// The references are strictly ordered from base to head. A reference
// is anything which 8000 can be represented by a distribution.Descriptor
References() []Descriptor

// Payload provides the serialized format of the manifest, in addition to
// the mediatype.
Payload() (mediatype string, payload []byte, err error)
}

// ManifestBuilder creates a manifest allowing one to include dependencies.
// Instances can be obtained from a version-specific manifest package. Manifest
// specific data is passed into the function which creates the builder.
type ManifestBuilder interface {
// Build creates the manifest from his builder.
Build() (Manifest, error)

// References returns a list of objects which have been added to this
// builder. The dependencies are returned in the order they were added,
// which should be from base to head.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should plants a seed of uncertainty.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll replace with 'will' 😢

References() []Descriptor

// AppendReference includes the given object in the manifest after any
// existing dependencies. If the add fails, such as when adding an
// unsupported dependency, an error may be returned.
AppendReference(dependency Descriptor) error
}

// ManifestService describes operations on image manifests.
type ManifestService interface {
// Exists returns true if the manifest exists.
Exists(ctx context.Context, dgst digest.Digest) (bool, error)

// Get retrieves the manifest specified by the given digest
Get(ctx context.Context, dgst digest.Digest) (Manifest, error)

// Put creates or updates the given manifest returning the manifest digest
Put(ctx context.Context, manifest Manifest) (digest.Digest, error)

// Delete removes the manifest specified by the given digest. Deleting
// a manifest that doesn't exist will return ErrManifestNotFound
Delete(ctx context.Context, dgst digest.Digest) error

// Enumerate fills 'manifests' with the manifests in this service up
// to the size of 'manifests' and returns 'n' for the number of entries
// which were filled. 'last' contains an offset in the manifest set
// and can be used to resume iteration.
Enumerate(ctx context.Context, manifests []Manifest, last Manifest) (n int, err error)
}
40 changes: 0 additions & 40 deletions registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,46 +70,6 @@ type Repository interface {
// way instances are created to better reflect internal dependency
// relationships.

// ManifestService provides operations on image manifests.
type ManifestService interface {
// Exists returns true if the manifest exists.
Exists(dgst digest.Digest) (bool, error)

// Get retrieves the identified by the digest, if it exists.
Get(dgst digest.Digest) (*schema1.SignedManifest, error)

// Delete removes the manifest, if it exists.
Delete(dgst digest.Digest) error

// Put creates or updates the manifest.
Put(manifest *schema1.SignedManifest) error

// TODO(stevvooe): The methods after this message should be moved to a
// discrete TagService, per active proposals.

// Tags lists the tags under the named repository.
Tags() ([]string, error)

// ExistsByTag returns true if the manifest exists.
ExistsByTag(tag string) (bool, error)

// GetByTag retrieves the named manifest, if it exists.
GetByTag(tag string, options ...ManifestServiceOption) (*schema1.SignedManifest, error)

// TODO(stevvooe): There are several changes that need to be done to this
// interface:
//
// 1. Allow explicit tagging with Tag(digest digest.Digest, tag string)
// 2. Support reading tags with a re-entrant reader to avoid large
// allocations in the registry.
// 3. Long-term: Provide All() method that lets one scroll through all of
// the manifest entries.
// 4. Long-term: break out concept of signing from manifests. This is
// really a part of the distribution sprint.
// 5. Long-term: Manifest should be an interface. This code shouldn't
// really be concerned with the storage format.
}

// SignatureService provides operations on signatures.
type SignatureService interface {
// Get retrieves all of the signature blobs for the specified digest.
Expand Down
31 changes: 31 additions & 0 deletions tags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package distribution

import (
"github.com/docker/distribution/context"
"github.com/docker/distribution/reference"
)

// TagService provides access to information about tagged objects.
type TagService interface {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this scoped to a global namespace or particular repository or both?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently a repository returns an instance to its tag service. In the future there will be a tag service. docker notary for instance.

// Get retrieves the descriptor identified by the tag. Some
// implementations may differentiate between "trusted" tags and
// "untrusted" tags. If a tag is & 6D40 quot;untrusted", the mapping will be returned
// as an ErrTagUntrusted error, with the target descriptor.
Get(ctx context.Context, ref reference.Tagged) (Descriptor, error)

// Tag associates the tag with the provided descriptor, updating the
// current association, if needed.
Tag(ctx context.Context, ref reference.Tagged, desc Descriptor) error

// Untag removes the given tag association
Untag(ctx context.Context, ref reference.Tagged) error

// Enumerate fills 'refs' with a lexigraphically sorted set of tags up to
// the size of 'refs' and returns 'n' for the number of entries which were
// filled. 'last' contains an offset in the tag set and can be used to resume
// iteration.
Enumerate(ctx context.Context, refs []reference.Tagged, last reference.Tagged) (n int, err error)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently I don't know of a way, how to create an empty reference.Tagged object. Which means I would always have to construct some "valid" tag object to pass as the last argument. Just realized how simple it is with just nil. Nevertheless, shouldn't the last argument be just reference.Reference?

What if I want to list all tags of just one repository? In case of repository scoped TagService it would be simple if I could pass an empty reference as last. In case of globally scoped TagService, it would be untrivial. Caller would have to choose some valid tag.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After conversing with @dmcgowan I came to the same conclusion: the reference.Tagged object is not suitable here because it is not designed to hold partial references. I've since changed these back to string arguments.


// Lookup returns the set of tags referencing the given digest
Lookup(ctx context.Context, digest digest.Descriptor) ([]reference.Tagged, error)
}
0