diff --git a/cli/cmd/compose/compose.go b/cli/cmd/compose/compose.go index 76eda7d9c..9108dc885 100644 --- a/cli/cmd/compose/compose.go +++ b/cli/cmd/compose/compose.go @@ -20,9 +20,9 @@ import ( "context" "github.com/compose-spec/compose-go/cli" - "github.com/spf13/pflag" - + "github.com/compose-spec/compose-go/types" "github.com/spf13/cobra" + "github.com/spf13/pflag" "github.com/docker/compose-cli/api/client" "github.com/docker/compose-cli/errdefs" @@ -100,3 +100,40 @@ func checkComposeSupport(ctx context.Context) error { return err } + +// +func filter(project *types.Project, services []string) error { + if len(services) == 0 { + // All services + return nil + } + + names := map[string]bool{} + err := addServiceNames(project, services, names) + if err != nil { + return err + } + var filtered types.Services + for _, s := range project.Services { + if _, ok := names[s.Name]; ok { + filtered = append(filtered, s) + } + } + project.Services = filtered + return nil +} + +func addServiceNames(project *types.Project, services []string, names map[string]bool) error { + for _, name := range services { + names[name] = true + service, err := project.GetService(name) + if err != nil { + return err + } + err = addServiceNames(project, service.GetDependencies(), names) + if err != nil { + return err + } + } + return nil +} diff --git a/cli/cmd/compose/compose_test.go b/cli/cmd/compose/compose_test.go new file mode 100644 index 000000000..49308d705 --- /dev/null +++ b/cli/cmd/compose/compose_test.go @@ -0,0 +1,53 @@ +/* + 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 compose + +import ( + "testing" + + "github.com/compose-spec/compose-go/types" + "gotest.tools/v3/assert" +) + +func TestFilterServices(t *testing.T) { + p := types.Project{ + Services: []types.ServiceConfig{ + { + Name: "foo", + Links: []string{"bar"}, + }, + { + Name: "bar", + NetworkMode: "service:zot", + }, + { + Name: "zot", + }, + { + Name: "qix", + }, + }, + } + err := filter(&p, []string{"bar"}) + assert.NilError(t, err) + + assert.Equal(t, len(p.Services), 2) + _, err = p.GetService("bar") + assert.NilError(t, err) + _, err = p.GetService("zot") + assert.NilError(t, err) +} diff --git a/cli/cmd/compose/up.go b/cli/cmd/compose/up.go index 359810f7e..aabdf578d 100644 --- a/cli/cmd/compose/up.go +++ b/cli/cmd/compose/up.go @@ -19,9 +19,8 @@ package compose import ( "context" - "github.com/spf13/cobra" - "github.com/compose-spec/compose-go/cli" + "github.com/spf13/cobra" "github.com/docker/compose-cli/api/client" "github.com/docker/compose-cli/context/store" @@ -31,9 +30,9 @@ import ( func upCommand(contextType string) *cobra.Command { opts := composeOptions{} upCmd := &cobra.Command{ - Use: "up", + Use: "up [SERVICE...]", RunE: func(cmd *cobra.Command, args []string) error { - return runUp(cmd.Context(), opts) + return runUp(cmd.Context(), opts, args) }, } upCmd.Flags().StringVarP(&opts.Name, "project-name", "p", "", "Project name") @@ -49,7 +48,7 @@ func upCommand(contextType string) *cobra.Command { return upCmd } -func runUp(ctx context.Context, opts composeOptions) error { +func runUp(ctx context.Context, opts composeOptions, services []string) error { c, err := client.New(ctx) if err != nil { return err @@ -61,10 +60,15 @@ func runUp(ctx context.Context, opts composeOptions) error { return "", err } project, err := cli.ProjectFromOptions(options) + if err != nil { + return "", err + } if opts.DomainName != "" { //arbitrarily set the domain name on the first service ; ACI backend will expose the entire project project.Services[0].DomainName = opts.DomainName } + + err = filter(project, services) if err != nil { return "", err }