Skip to content

Commit 9d73cc8

Browse files
authored
Merge pull request docker#9148 from arhemd/issue#9147
Using start, stop, restart from outside the working directory using --project-name (docker#9147)
2 parents fd676ad + 9c68c76 commit 9d73cc8

File tree

15 files changed

+125
-91
lines changed

15 files changed

+125
-91
lines changed

cmd/compose/remove.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ func runRemove(ctx context.Context, backend api.Service, opts removeOptions, ser
6565
}
6666

6767
if opts.stop {
68-
err := backend.Stop(ctx, project, api.StopOptions{
68+
err := backend.Stop(ctx, project.Name, api.StopOptions{
6969
Services: services,
7070
})
7171
if err != nil {

cmd/compose/restart.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,13 @@ func restartCommand(p *projectOptions, backend api.Service) *cobra.Command {
4949
}
5050

5151
func runRestart(ctx context.Context, backend api.Service, opts restartOptions, services []string) error {
52-
project, err := opts.toProject(services)
52+
projectName, err := opts.toProjectName()
5353
if err != nil {
5454
return err
5555
}
5656

5757
timeout := time.Duration(opts.timeout) * time.Second
58-
return backend.Restart(ctx, project, api.RestartOptions{
58+
return backend.Restart(ctx, projectName, api.RestartOptions{
5959
Timeout: &timeout,
6060
Services: services,
6161
})

cmd/compose/run.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,5 +240,5 @@ func startDependencies(ctx context.Context, backend api.Service, project types.P
240240
if err := backend.Create(ctx, &project, api.CreateOptions{}); err != nil {
241241
return err
242242
}
243-
return backend.Start(ctx, &project, api.StartOptions{})
243+
return backend.Start(ctx, project.Name, api.StartOptions{})
244244
}

cmd/compose/start.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,12 @@ func startCommand(p *projectOptions, backend api.Service) *cobra.Command {
4343
}
4444

4545
func runStart(ctx context.Context, backend api.Service, opts startOptions, services []string) error {
46-
project, err := opts.toProject(services)
46+
projectName, err := opts.toProjectName()
4747
if err != nil {
4848
return err
4949
}
5050

51-
return backend.Start(ctx, project, api.StartOptions{})
51+
return backend.Start(ctx, projectName, api.StartOptions{
52+
AttachTo: services,
53+
})
5254
}

cmd/compose/stop.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ func stopCommand(p *projectOptions, backend api.Service) *cobra.Command {
5353
}
5454

5555
func runStop(ctx context.Context, backend api.Service, opts stopOptions, services []string) error {
56-
project, err := opts.toProject(services)
56+
projectName, err := opts.toProjectName()
5757
if err != nil {
5858
return err
5959
}
@@ -63,7 +63,7 @@ func runStop(ctx context.Context, backend api.Service, opts stopOptions, service
6363
timeoutValue := time.Duration(opts.timeout) * time.Second
6464
timeout = &timeoutValue
6565
}
66-
return backend.Stop(ctx, project, api.StopOptions{
66+
return backend.Stop(ctx, projectName, api.StopOptions{
6767
Timeout: timeout,
6868
Services: services,
6969
})

pkg/api/api.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@ type Service interface {
3737
// Create executes the equivalent to a `compose create`
3838
Create(ctx context.Context, project *types.Project, opts CreateOptions) error
3939
// Start executes the equivalent to a `compose start`
40-
Start(ctx context.Context, project *types.Project, options StartOptions) error
40+
Start(ctx context.Context, projectName string, options StartOptions) error
4141
// Restart restarts containers
42-
Restart(ctx context.Context, project *types.Project, options RestartOptions) error
42+
Restart(ctx context.Context, projectName string, options RestartOptions) error
4343
// Stop executes the equivalent to a `compose stop`
44-
Stop(ctx context.Context, project *types.Project, options StopOptions) error
44+
Stop(ctx context.Context, projectName string, options StopOptions) error
4545
// Up executes the equivalent to a `compose up`
4646
Up(ctx context.Context, project *types.Project, options UpOptions) error
4747
// Down executes the equivalent to a `compose down`

pkg/api/proxy.go

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ type ServiceProxy struct {
2828
PushFn func(ctx context.Context, project *types.Project, options PushOptions) error
2929
PullFn func(ctx context.Context, project *types.Project, opts PullOptions) error
3030
CreateFn func(ctx context.Context, project *types.Project, opts CreateOptions) error
31-
StartFn func(ctx context.Context, project *types.Project, options StartOptions) error
32-
RestartFn func(ctx context.Context, project *types.Project, options RestartOptions) error
33-
StopFn func(ctx context.Context, project *types.Project, options StopOptions) error
31+
StartFn func(ctx context.Context, projectName string, options StartOptions) error
32+
RestartFn func(ctx context.Context, projectName string, options RestartOptions) error
33+
StopFn func(ctx context.Context, projectName string, options StopOptions) error
3434
UpFn func(ctx context.Context, project *types.Project, options UpOptions) error
3535
DownFn func(ctx context.Context, projectName string, options DownOptions) error
3636
LogsFn func(ctx context.Context, projectName string, consumer LogConsumer, options LogOptions) error
@@ -141,36 +141,27 @@ func (s *ServiceProxy) Create(ctx context.Context, project *types.Project, optio
141141
}
142142

143143
// Start implements Service interface
144-
func (s *ServiceProxy) Start(ctx context.Context, project *types.Project, options StartOptions) error {
144+
func (s *ServiceProxy) Start(ctx context.Context, projectName string, options StartOptions) error {
145145
if s.StartFn == nil {
146146
return ErrNotImplemented
147147
}
148-
for _, i := range s.interceptors {
149-
i(ctx, project)
150-
}
151-
return s.StartFn(ctx, project, options)
148+
return s.StartFn(ctx, projectName, options)
152149
}
153150

154151
// Restart implements Service interface
155-
func (s *ServiceProxy) Restart(ctx context.Context, project *types.Project, options RestartOptions) error {
152+
func (s *ServiceProxy) Restart(ctx context.Context, projectName string, options RestartOptions) error {
156153
if s.RestartFn == nil {
157154
return ErrNotImplemented
158155
}
159-
for _, i := range s.interceptors {
160-
i(ctx, project)
161-
}
162-
return s.RestartFn(ctx, project, options)
156+
return s.RestartFn(ctx, projectName, options)
163157
}
164158

165159
// Stop implements Service interface
166-
func (s *ServiceProxy) Stop(ctx context.Context, project *types.Project, options StopOptions) error {
160+
func (s *ServiceProxy) Stop(ctx context.Context, projectName string, options StopOptions) error {
167161
if s.StopFn == nil {
168162
return ErrNotImplemented
169163
}
170-
for _, i := range s.interceptors {
171-
i(ctx, project)
172-
}
173-
return s.StopFn(ctx, project, options)
164+
return s.StopFn(ctx, projectName, options)
174165
}
175166

176167
// Up implements Service interface

pkg/compose/compose.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"strings"
2525

2626
"github.com/docker/compose/v2/pkg/api"
27+
"github.com/pkg/errors"
2728

2829
"github.com/compose-spec/compose-go/types"
2930
"github.com/docker/cli/cli/config/configfile"
@@ -92,3 +93,59 @@ func escapeDollarSign(marshal []byte) []byte {
9293
escDollar := []byte{'$', '$'}
9394
return bytes.ReplaceAll(marshal, dollar, escDollar)
9495
}
96+
97+
// projectFromName builds a types.Project based on actual resources with compose labels set
98+
func (s *composeService) projectFromName(containers Containers, projectName string, services ...string) (*types.Project, error) {
99+
project := &types.Project{
100+
Name: projectName,
101+
}
102+
if len(containers) == 0 {
103+
return project, errors.New("no such project: " + projectName)
104+
}
105+
set := map[string]*types.ServiceConfig{}
106+
for _, c := range containers {
107+
serviceLabel := c.Labels[api.ServiceLabel]
108+
_, ok := set[serviceLabel]
109+
if !ok {
110+
set[serviceLabel] = &types.ServiceConfig{
111+
Name: serviceLabel,
112+
Image: c.Image,
113+
Labels: c.Labels,
114+
}
115+
}
116+
set[serviceLabel].Scale++
117+
}
118+
for _, service := range set {
119+
dependencies := service.Labels[api.DependenciesLabel]
120+
if len(dependencies) > 0 {
121+
service.DependsOn = types.DependsOnConfig{}
122+
for _, dc := range strings.Split(dependencies, ",") {
123+
dcArr := strings.Split(dc, ":")
124+
condition := ServiceConditionRunningOrHealthy
125+
dependency := dcArr[0]
126+
127+
// backward compatibility
128+
if len(dcArr) > 1 {
129+
condition = dcArr[1]
130+
}
131+
service.DependsOn[dependency] = types.ServiceDependency{Condition: condition}
132+
}
133+
}
134+
project.Services = append(project.Services, *service)
135+
}
136+
SERVICES:
137+
for _, qs := range services {
138+
for _, es := range project.Services {
139+
if es.Name == qs {
140+
continue SERVICES
141+
}
142+
}
143+
return project, errors.New("no such service: " + qs)
144+
}
145+
err := project.ForServices(services)
146+
if err != nil {
147+
return project, err
148+
}
149+
150+
return project, nil
151+
}

pkg/compose/create.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -432,8 +432,8 @@ func (s *composeService) prepareLabels(service types.ServiceConfig, number int)
432432
labels[api.ContainerNumberLabel] = strconv.Itoa(number)
433433

434434
var dependencies []string
435-
for s := range service.DependsOn {
436-
dependencies = append(dependencies, s)
435+
for s, d := range service.DependsOn {
436+
dependencies = append(dependencies, s+":"+d.Condition)
437437
}
438438
labels[api.DependenciesLabel] = strings.Join(dependencies, ",")
439439
return labels, nil

pkg/compose/down.go

Lines changed: 6 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ func (s *composeService) Down(ctx context.Context, projectName string, options a
4141
}
4242

4343
func (s *composeService) down(ctx context.Context, projectName string, options api.DownOptions) error {
44+
builtFromResources := options.Project == nil
4445
w := progress.ContextWriter(ctx)
4546
resourceToRemove := false
4647

@@ -50,8 +51,8 @@ func (s *composeService) down(ctx context.Context, projectName string, options a
5051
return err
5152
}
5253

53-
if options.Project == nil {
54-
options.Project, err = s.projectFromLabels(ctx, containers.filter(isNotOneOff), projectName)
54+
if builtFromResources {
55+
options.Project, err = s.getProjectWithVolumes(ctx, containers, projectName)
5556
if err != nil {
5657
return err
5758
}
@@ -232,34 +233,9 @@ func (s *composeService) removeContainers(ctx context.Context, w progress.Writer
232233
return eg.Wait()
233234
}
234235

235-
// projectFromLabels builds a types.Project based on actual resources with compose labels set
236-
func (s *composeService) projectFromLabels(ctx context.Context, containers Containers, projectName string) (*types.Project, error) {
237-
project := &types.Project{
238-
Name: projectName,
239-
}
240-
if len(containers) == 0 {
241-
return project, nil
242-
}
243-
set := map[string]moby.Container{}
244-
for _, c := range containers {
245-
set[c.Labels[api.ServiceLabel]] = c
246-
}
247-
for s, c := range set {
248-
service := types.ServiceConfig{
249-
Name: s,
250-
Image: c.Image,
251-
Labels: c.Labels,
252-
}
253-
dependencies := c.Labels[api.DependenciesLabel]
254-
if len(dependencies) > 0 {
255-
service.DependsOn = types.DependsOnConfig{}
256-
for _, d := range strings.Split(dependencies, ",") {
257-
service.DependsOn[d] = types.ServiceDependency{}
258-
}
259-
}
260-
project.Services = append(project.Services, service)
261-
}
262-
236+
func (s *composeService) getProjectWithVolumes(ctx context.Context, containers Containers, projectName string) (*types.Project, error) {
237+
containers = containers.filter(isNotOneOff)
238+
project, _ := s.projectFromName(containers, projectName)
263239
volumes, err := s.apiClient.VolumeList(ctx, filters.NewArgs(projectFilter(projectName)))
264240
if err != nil {
265241
return nil, err
@@ -273,6 +249,5 @@ func (s *composeService) projectFromLabels(ctx context.Context, containers Conta
273249
Labels: vol.Labels,
274250
}
275251
}
276-
277252
return project, nil
278253
}

0 commit comments

Comments
 (0)