mirror of https://github.com/docker/compose.git
Compare commits
16 Commits
Author | SHA1 | Date |
---|---|---|
|
0dc9852c67 | |
|
a478702236 | |
|
2c12ad19db | |
|
038ea8441a | |
|
9e98e6101e | |
|
52f04229c0 | |
|
28895d0322 | |
|
a926f7d717 | |
|
fe046915eb | |
|
adbd61e5d6 | |
|
e37ac04329 | |
|
cab2c2a44e | |
|
1946de598d | |
|
8e29a138aa | |
|
3c8da0afee | |
|
1b12c867c5 |
4
go.mod
4
go.mod
|
@ -15,9 +15,9 @@ require (
|
|||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/distribution/reference v0.6.0
|
||||
github.com/docker/buildx v0.26.1
|
||||
github.com/docker/cli v28.3.2+incompatible
|
||||
github.com/docker/cli v28.3.3+incompatible
|
||||
github.com/docker/cli-docs-tool v0.10.0
|
||||
github.com/docker/docker v28.3.2+incompatible
|
||||
github.com/docker/docker v28.3.3+incompatible
|
||||
github.com/docker/go-connections v0.5.0
|
||||
github.com/docker/go-units v0.5.0
|
||||
github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203
|
||||
|
|
8
go.sum
8
go.sum
|
@ -129,15 +129,15 @@ github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxK
|
|||
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/docker/buildx v0.26.1 h1:nlj3bVhHK9fV7g6floRvGhPcR0u2hxCPMmObCS1ZKL4=
|
||||
github.com/docker/buildx v0.26.1/go.mod h1:oxMC30cSHPaCCkY2j+EqN7uxFikjSzVC0c44lo9b4Fo=
|
||||
github.com/docker/cli v28.3.2+incompatible h1:mOt9fcLE7zaACbxW1GeS65RI67wIJrTnqS3hP2huFsY=
|
||||
github.com/docker/cli v28.3.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/cli v28.3.3+incompatible h1:fp9ZHAr1WWPGdIWBM1b3zLtgCF+83gRdVMTJsUeiyAo=
|
||||
github.com/docker/cli v28.3.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/cli-docs-tool v0.10.0 h1:bOD6mKynPQgojQi3s2jgcUWGp/Ebqy1SeCr9VfKQLLU=
|
||||
github.com/docker/cli-docs-tool v0.10.0/go.mod h1:5EM5zPnT2E7yCLERZmrDA234Vwn09fzRHP4aX1qwp1U=
|
||||
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
|
||||
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v28.3.2+incompatible h1:wn66NJ6pWB1vBZIilP8G3qQPqHy5XymfYn5vsqeA5oA=
|
||||
github.com/docker/docker v28.3.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v28.3.3+incompatible h1:Dypm25kh4rmk49v1eiVbsAtpAsYURjYkaKubwuBdxEI=
|
||||
github.com/docker/docker v28.3.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.9.3 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqIjCBS4wrsOh9yRqcz8=
|
||||
github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo=
|
||||
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
"github.com/docker/cli/cli/streams"
|
||||
)
|
||||
|
||||
// Streams defines the standard streams (stdin, stdout, stderr) used by the CLI.
|
||||
type Streams interface {
|
||||
Out() *streams.Out
|
||||
Err() *streams.Out
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
|
||||
"github.com/docker/compose/v2/internal"
|
||||
|
@ -65,9 +63,6 @@ var ComposeVersion string
|
|||
func init() {
|
||||
v, err := version.NewVersion(internal.Version)
|
||||
if err == nil {
|
||||
segments := v.Segments()
|
||||
if len(segments) > 2 {
|
||||
ComposeVersion = fmt.Sprintf("%d.%d.%d", segments[0], segments[1], segments[2])
|
||||
}
|
||||
ComposeVersion = v.Core().String()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
Copyright 2020 Docker Compose CLI authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/docker/compose/v2/internal"
|
||||
"github.com/hashicorp/go-version"
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
func TestComposeVersionInitialization(t *testing.T) {
|
||||
v, err := version.NewVersion(internal.Version)
|
||||
if err != nil {
|
||||
assert.Equal(t, "", ComposeVersion, "ComposeVersion should be empty for a non-semver internal version (e.g. 'devel')")
|
||||
} else {
|
||||
expected := v.Core().String()
|
||||
assert.Equal(t, expected, ComposeVersion, "ComposeVersion should be the core of internal.Version")
|
||||
}
|
||||
}
|
|
@ -33,6 +33,8 @@ import (
|
|||
const (
|
||||
TransformerLabel = "com.docker.compose.bridge"
|
||||
DefaultTransformerImage = "docker/compose-bridge-kubernetes"
|
||||
|
||||
templatesPath = "/templates"
|
||||
)
|
||||
|
||||
type CreateTransformerOptions struct {
|
||||
|
@ -73,7 +75,7 @@ func CreateTransformer(ctx context.Context, dockerCli command.Cli, options Creat
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
content, stat, err := dockerCli.Client().CopyFromContainer(ctx, created.ID, "/templates")
|
||||
content, stat, err := dockerCli.Client().CopyFromContainer(ctx, created.ID, templatesPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -82,7 +84,7 @@ func CreateTransformer(ctx context.Context, dockerCli command.Cli, options Creat
|
|||
}()
|
||||
|
||||
srcInfo := archive.CopyInfo{
|
||||
Path: "/templates",
|
||||
Path: templatesPath,
|
||||
Exists: true,
|
||||
IsDir: stat.Mode.IsDir(),
|
||||
}
|
||||
|
|
|
@ -130,14 +130,16 @@ type buildStatus struct {
|
|||
func (s *composeService) doBuildBake(ctx context.Context, project *types.Project, serviceToBeBuild types.Services, options api.BuildOptions) (map[string]string, error) { //nolint:gocyclo
|
||||
eg := errgroup.Group{}
|
||||
ch := make(chan *client.SolveStatus)
|
||||
if options.Progress == progress.ModeAuto {
|
||||
options.Progress = os.Getenv("BUILDKIT_PROGRESS")
|
||||
}
|
||||
displayMode := progressui.DisplayMode(options.Progress)
|
||||
out := options.Out
|
||||
if out == nil {
|
||||
cout := s.dockerCli.Out()
|
||||
if !cout.IsTerminal() {
|
||||
if !s.dockerCli.Out().IsTerminal() {
|
||||
displayMode = progressui.PlainMode
|
||||
}
|
||||
out = cout
|
||||
out = os.Stdout // should be s.dockerCli.Out(), but NewDisplay require access to the underlying *File
|
||||
}
|
||||
display, err := progressui.NewDisplay(out, displayMode)
|
||||
if err != nil {
|
||||
|
|
|
@ -195,7 +195,7 @@ func (m *modelAPI) SetModelVariables(ctx context.Context, project *types.Project
|
|||
if modelConfig != nil && modelConfig.ModelVariable != "" {
|
||||
variable = modelConfig.ModelVariable
|
||||
} else {
|
||||
variable = varPrefix
|
||||
variable = varPrefix + "_MODEL"
|
||||
}
|
||||
service.Environment[variable] = &model.Model
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@ import (
|
|||
|
||||
"github.com/compose-spec/compose-go/v2/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
func (s *composeService) Start(ctx context.Context, projectName string, options api.StartOptions) error {
|
||||
|
@ -52,18 +51,6 @@ func (s *composeService) start(ctx context.Context, projectName string, options
|
|||
}
|
||||
}
|
||||
|
||||
// use an independent context tied to the errgroup for background attach operations
|
||||
// the primary context is still used for other operations
|
||||
// this means that once any attach operation fails, all other attaches are cancelled,
|
||||
// but an attach failing won't interfere with the rest of the start
|
||||
eg, attachCtx := errgroup.WithContext(ctx)
|
||||
if listener != nil {
|
||||
_, err := s.attach(attachCtx, project, listener, options.AttachTo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
var containers Containers
|
||||
containers, err := s.apiClient().ContainerList(ctx, containerType.ListOptions{
|
||||
Filters: filters.NewArgs(
|
||||
|
@ -111,7 +98,7 @@ func (s *composeService) start(ctx context.Context, projectName string, options
|
|||
}
|
||||
}
|
||||
|
||||
return eg.Wait()
|
||||
return nil
|
||||
}
|
||||
|
||||
// getDependencyCondition checks if service is depended on by other services
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"slices"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
|
||||
|
@ -34,6 +35,7 @@ import (
|
|||
"github.com/eiannone/keyboard"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
func (s *composeService) Up(ctx context.Context, project *types.Project, options api.UpOptions) error { //nolint:gocyclo
|
||||
|
@ -205,29 +207,44 @@ func (s *composeService) Up(ctx context.Context, project *types.Project, options
|
|||
})
|
||||
}
|
||||
|
||||
// use an independent context tied to the errgroup for background attach operations
|
||||
// the primary context is still used for other operations
|
||||
// this means that once any attach operation fails, all other attaches are cancelled,
|
||||
// but an attach failing won't interfere with the rest of the start
|
||||
_, attachCtx := errgroup.WithContext(ctx)
|
||||
containers, err := s.attach(attachCtx, project, printer.HandleEvent, options.Start.AttachTo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
attached := make([]string, len(containers))
|
||||
for i, ctr := range containers {
|
||||
attached[i] = ctr.ID
|
||||
}
|
||||
|
||||
monitor.withListener(func(event api.ContainerEvent) {
|
||||
if event.Type != api.ContainerEventStarted {
|
||||
return
|
||||
}
|
||||
if event.Restarting || event.Container.Labels[api.ContainerReplaceLabel] != "" {
|
||||
eg.Go(func() error {
|
||||
ctr, err := s.apiClient().ContainerInspect(ctx, event.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = s.doLogContainer(ctx, options.Start.Attach, event.Source, ctr, api.LogOptions{
|
||||
Follow: true,
|
||||
Since: ctr.State.StartedAt,
|
||||
})
|
||||
if errdefs.IsNotImplemented(err) {
|
||||
// container may be configured with logging_driver: none
|
||||
// as container already started, we might miss the very first logs. But still better than none
|
||||
return s.doAttachContainer(ctx, event.Service, event.ID, event.Source, printer.HandleEvent)
|
||||
}
|
||||
return err
|
||||
})
|
||||
if slices.Contains(attached, event.ID) {
|
||||
return
|
||||
}
|
||||
eg.Go(func() error {
|
||||
ctr, err := s.apiClient().ContainerInspect(ctx, event.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = s.doLogContainer(ctx, options.Start.Attach, event.Source, ctr, api.LogOptions{
|
||||
Follow: true,
|
||||
Since: ctr.State.StartedAt,
|
||||
})
|
||||
if errdefs.IsNotImplemented(err) {
|
||||
// container may be configured with logging_driver: none
|
||||
// as container already started, we might miss the very first logs. But still better than none
|
||||
return s.doAttachContainer(ctx, event.Service, event.ID, event.Source, printer.HandleEvent)
|
||||
}
|
||||
return err
|
||||
})
|
||||
})
|
||||
|
||||
eg.Go(func() error {
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
Copyright 2024 Docker Compose CLI authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package progress
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
func TestJsonWriter_Event(t *testing.T) {
|
||||
var out bytes.Buffer
|
||||
w := &jsonWriter{
|
||||
out: &out,
|
||||
done: make(chan bool),
|
||||
dryRun: true,
|
||||
}
|
||||
|
||||
event := Event{
|
||||
ID: "service1",
|
||||
ParentID: "project",
|
||||
Text: "Creating",
|
||||
StatusText: "Working",
|
||||
Current: 50,
|
||||
Total: 100,
|
||||
Percent: 50,
|
||||
}
|
||||
w.Event(event)
|
||||
|
||||
var actual jsonMessage
|
||||
err := json.Unmarshal(out.Bytes(), &actual)
|
||||
assert.NilError(t, err)
|
||||
|
||||
expected := jsonMessage{
|
||||
DryRun: true,
|
||||
ID: event.ID,
|
||||
ParentID: event.ParentID,
|
||||
Text: event.Text,
|
||||
Status: event.StatusText,
|
||||
Current: event.Current,
|
||||
Total: event.Total,
|
||||
Percent: event.Percent,
|
||||
}
|
||||
assert.DeepEqual(t, expected, actual)
|
||||
}
|
||||
|
||||
func TestJsonWriter_TailMsgf(t *testing.T) {
|
||||
var out bytes.Buffer
|
||||
w := &jsonWriter{
|
||||
out: &out,
|
||||
done: make(chan bool),
|
||||
dryRun: false,
|
||||
}
|
||||
|
||||
go func() {
|
||||
_ = w.Start(context.Background())
|
||||
}()
|
||||
|
||||
w.TailMsgf("hello %s", "world")
|
||||
|
||||
w.Stop()
|
||||
|
||||
var actual jsonMessage
|
||||
err := json.Unmarshal(out.Bytes(), &actual)
|
||||
assert.NilError(t, err)
|
||||
|
||||
expected := jsonMessage{
|
||||
Tail: true,
|
||||
Text: "hello world",
|
||||
}
|
||||
assert.DeepEqual(t, expected, actual)
|
||||
}
|
Loading…
Reference in New Issue