Skip to content

Commit 5ca35c8

Browse files
committed
implement publish
Signed-off-by: Nicolas De Loof <[email protected]>
1 parent 805541b commit 5ca35c8

File tree

2 files changed

+121
-4
lines changed

2 files changed

+121
-4
lines changed

pkg/compose/publish.go

Lines changed: 115 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,136 @@ package compose
1818

1919
import (
2020
"context"
21+
"encoding/json"
22+
"os"
2123

2224
"github.com/compose-spec/compose-go/types"
2325
"github.com/distribution/reference"
26+
"github.com/docker/buildx/util/imagetools"
2427
"github.com/docker/compose/v2/pkg/api"
28+
"github.com/docker/compose/v2/pkg/progress"
29+
"github.com/opencontainers/go-digest"
30+
"github.com/opencontainers/image-spec/specs-go"
31+
v1 "github.com/opencontainers/image-spec/specs-go/v1"
2532
)
2633

2734
func (s *composeService) Publish(ctx context.Context, project *types.Project, repository string, options api.PublishOptions) error {
35+
return progress.RunWithTitle(ctx, func(ctx context.Context) error {
36+
return s.publish(ctx, project, repository, options)
37+
}, s.stdinfo(), "Publishing")
38+
}
39+
40+
func (s *composeService) publish(ctx context.Context, project *types.Project, repository string, options api.PublishOptions) error {
2841
err := s.Push(ctx, project, api.PushOptions{})
2942
if err != nil {
3043
return err
3144
}
3245

33-
_, err = reference.ParseDockerRef(repository)
46+
w := progress.ContextWriter(ctx)
47+
48+
named, err := reference.ParseDockerRef(repository)
49+
if err != nil {
50+
return err
51+
}
52+
53+
resolver := imagetools.New(imagetools.Opt{
54+
Auth: s.configFile(),
55+
})
56+
57+
var layers []v1.Descriptor
58+
for _, file := range project.ComposeFiles {
59+
f, err := os.ReadFile(file)
60+
if err != nil {
61+
return err
62+
}
63+
64+
w.Event(progress.Event{
65+
ID: file,
66+
Text: "publishing",
67+
Status: progress.Working,
68+
})
69+
layer := v1.Descriptor{
70+
MediaType: "application/vnd.docker.compose.file+yaml",
71+
Digest: digest.FromString(string(f)),
72+
Size: int64(len(f)),
73+
Annotations: map[string]string{
74+
"com.docker.compose": api.ComposeVersion,
75+
},
76+
}
77+
layers = append(layers, layer)
78+
err = resolver.Push(ctx, named, layer, f)
79+
if err != nil {
80+
w.Event(progress.Event{
81+
ID: file,
82+
Text: "publishing",
83+
Status: progress.Error,
84+
})
85+
86+
return err
87+
}
88+
89+
w.Event(progress.Event{
90+
ID: file,
91+
Text: "published",
92+
Status: progress.Done,
93+
})
94+
}
95+
96+
emptyConfig, err := json.Marshal(v1.ImageConfig{})
97+
if err != nil {
98+
return err
99+
}
100+
configDescriptor := v1.Descriptor{
101+
MediaType: "application/vnd.docker.compose.project",
102+
Digest: digest.FromBytes(emptyConfig),
103+
Size: int64(len(emptyConfig)),
104+
Annotations: map[string]string{
105+
"com.docker.compose.version": api.ComposeVersion,
106+
},
107+
}
108+
err = resolver.Push(ctx, named, configDescriptor, emptyConfig)
109+
if err != nil {
110+
return err
111+
}
112+
113+
imageManifest, err := json.Marshal(v1.Manifest{
114+
Versioned: specs.Versioned{SchemaVersion: 2},
115+
MediaType: v1.MediaTypeImageManifest,
116+
ArtifactType: "application/vnd.docker.compose.project",
117+
Config: configDescriptor,
118+
Layers: layers,
119+
})
34120
if err != nil {
35121
return err
36122
}
37123

38-
// TODO publish project.ComposeFiles
124+
w.Event(progress.Event{
125+
ID: repository,
126+
Text: "publishing",
127+
Status: progress.Working,
128+
})
39129

40-
return api.ErrNotImplemented
130+
err = resolver.Push(ctx, named, v1.Descriptor{
131+
MediaType: v1.MediaTypeImageManifest,
132+
Digest: digest.FromString(string(imageManifest)),
133+
Size: int64(len(imageManifest)),
134+
Annotations: map[string]string{
135+
"com.docker.compose.version": api.ComposeVersion,
136+
},
137+
ArtifactType: "application/vnd.docker.compose.project",
138+
}, imageManifest)
139+
if err != nil {
140+
w.Event(progress.Event{
141+
ID: repository,
142+
Text: "publishing",
143+
Status: progress.Error,
144+
})
145+
return err
146+
}
147+
w.Event(progress.Event{
148+
ID: repository,
149+
Text: "published",
150+
Status: progress.Done,
151+
})
152+
return nil
41153
}

pkg/remote/oci.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ type ociRemoteLoader struct {
7070
offline bool
7171
}
7272

73-
const prefix = "oci:"
73+
const prefix = "oci://"
7474

7575
func (g ociRemoteLoader) Accept(path string) bool {
7676
return strings.HasPrefix(path, prefix)
@@ -117,6 +117,11 @@ func (g ociRemoteLoader) Load(ctx context.Context, path string) (string, error)
117117
if err != nil {
118118
return "", err
119119
}
120+
121+
if descriptor.Config.MediaType != "application/vnd.docker.compose.project" {
122+
return "", fmt.Errorf("%s is not a compose project OCI artifact, but %s", ref.String(), descriptor.Config.MediaType)
123+
}
124+
120125
for i, layer := range descriptor.Layers {
121126
digested, err := reference.WithDigest(ref, layer.Digest)
122127
if err != nil {

0 commit comments

Comments
 (0)