implement publish

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
Nicolas De Loof 2023-09-15 19:48:21 +02:00 committed by Nicolas De loof
parent 805541be9d
commit 5ca35c88be
2 changed files with 121 additions and 4 deletions

View File

@ -18,24 +18,136 @@ package compose
import ( import (
"context" "context"
"encoding/json"
"os"
"github.com/compose-spec/compose-go/types" "github.com/compose-spec/compose-go/types"
"github.com/distribution/reference" "github.com/distribution/reference"
"github.com/docker/buildx/util/imagetools"
"github.com/docker/compose/v2/pkg/api" "github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/progress"
"github.com/opencontainers/go-digest"
"github.com/opencontainers/image-spec/specs-go"
v1 "github.com/opencontainers/image-spec/specs-go/v1"
) )
func (s *composeService) Publish(ctx context.Context, project *types.Project, repository string, options api.PublishOptions) error { func (s *composeService) Publish(ctx context.Context, project *types.Project, repository string, options api.PublishOptions) error {
return progress.RunWithTitle(ctx, func(ctx context.Context) error {
return s.publish(ctx, project, repository, options)
}, s.stdinfo(), "Publishing")
}
func (s *composeService) publish(ctx context.Context, project *types.Project, repository string, options api.PublishOptions) error {
err := s.Push(ctx, project, api.PushOptions{}) err := s.Push(ctx, project, api.PushOptions{})
if err != nil { if err != nil {
return err return err
} }
_, err = reference.ParseDockerRef(repository) w := progress.ContextWriter(ctx)
named, err := reference.ParseDockerRef(repository)
if err != nil { if err != nil {
return err return err
} }
// TODO publish project.ComposeFiles resolver := imagetools.New(imagetools.Opt{
Auth: s.configFile(),
})
return api.ErrNotImplemented var layers []v1.Descriptor
for _, file := range project.ComposeFiles {
f, err := os.ReadFile(file)
if err != nil {
return err
}
w.Event(progress.Event{
ID: file,
Text: "publishing",
Status: progress.Working,
})
layer := v1.Descriptor{
MediaType: "application/vnd.docker.compose.file+yaml",
Digest: digest.FromString(string(f)),
Size: int64(len(f)),
Annotations: map[string]string{
"com.docker.compose": api.ComposeVersion,
},
}
layers = append(layers, layer)
err = resolver.Push(ctx, named, layer, f)
if err != nil {
w.Event(progress.Event{
ID: file,
Text: "publishing",
Status: progress.Error,
})
return err
}
w.Event(progress.Event{
ID: file,
Text: "published",
Status: progress.Done,
})
}
emptyConfig, err := json.Marshal(v1.ImageConfig{})
if err != nil {
return err
}
configDescriptor := v1.Descriptor{
MediaType: "application/vnd.docker.compose.project",
Digest: digest.FromBytes(emptyConfig),
Size: int64(len(emptyConfig)),
Annotations: map[string]string{
"com.docker.compose.version": api.ComposeVersion,
},
}
err = resolver.Push(ctx, named, configDescriptor, emptyConfig)
if err != nil {
return err
}
imageManifest, err := json.Marshal(v1.Manifest{
Versioned: specs.Versioned{SchemaVersion: 2},
MediaType: v1.MediaTypeImageManifest,
ArtifactType: "application/vnd.docker.compose.project",
Config: configDescriptor,
Layers: layers,
})
if err != nil {
return err
}
w.Event(progress.Event{
ID: repository,
Text: "publishing",
Status: progress.Working,
})
err = resolver.Push(ctx, named, v1.Descriptor{
MediaType: v1.MediaTypeImageManifest,
Digest: digest.FromString(string(imageManifest)),
Size: int64(len(imageManifest)),
Annotations: map[string]string{
"com.docker.compose.version": api.ComposeVersion,
},
ArtifactType: "application/vnd.docker.compose.project",
}, imageManifest)
if err != nil {
w.Event(progress.Event{
ID: repository,
Text: "publishing",
Status: progress.Error,
})
return err
}
w.Event(progress.Event{
ID: repository,
Text: "published",
Status: progress.Done,
})
return nil
} }

View File

@ -70,7 +70,7 @@ type ociRemoteLoader struct {
offline bool offline bool
} }
const prefix = "oci:" const prefix = "oci://"
func (g ociRemoteLoader) Accept(path string) bool { func (g ociRemoteLoader) Accept(path string) bool {
return strings.HasPrefix(path, prefix) return strings.HasPrefix(path, prefix)
@ -117,6 +117,11 @@ func (g ociRemoteLoader) Load(ctx context.Context, path string) (string, error)
if err != nil { if err != nil {
return "", err return "", err
} }
if descriptor.Config.MediaType != "application/vnd.docker.compose.project" {
return "", fmt.Errorf("%s is not a compose project OCI artifact, but %s", ref.String(), descriptor.Config.MediaType)
}
for i, layer := range descriptor.Layers { for i, layer := range descriptor.Layers {
digested, err := reference.WithDigest(ref, layer.Digest) digested, err := reference.WithDigest(ref, layer.Digest)
if err != nil { if err != nil {