diff --git a/cli/command/stack/deploy_composefile.go b/cli/command/stack/deploy_composefile.go index 16d583ed99..e511a6f127 100644 --- a/cli/command/stack/deploy_composefile.go +++ b/cli/command/stack/deploy_composefile.go @@ -2,6 +2,7 @@ package stack import ( "fmt" + "io" "io/ioutil" "os" "path/filepath" @@ -22,7 +23,7 @@ import ( ) func deployCompose(ctx context.Context, dockerCli command.Cli, opts deployOptions) error { - configDetails, err := getConfigDetails(opts.composefile) + configDetails, err := getConfigDetails(opts.composefile, dockerCli.In()) if err != nil { return err } @@ -118,16 +119,24 @@ func propertyWarnings(properties map[string]string) string { return strings.Join(msgs, "\n\n") } -func getConfigDetails(composefile string) (composetypes.ConfigDetails, error) { +func getConfigDetails(composefile string, stdin io.Reader) (composetypes.ConfigDetails, error) { var details composetypes.ConfigDetails - absPath, err := filepath.Abs(composefile) - if err != nil { - return details, err + if composefile == "-" { + workingDir, err := os.Getwd() + if err != nil { + return details, err + } + details.WorkingDir = workingDir + } else { + absPath, err := filepath.Abs(composefile) + if err != nil { + return details, err + } + details.WorkingDir = filepath.Dir(absPath) } - details.WorkingDir = filepath.Dir(absPath) - configFile, err := getConfigFile(composefile) + configFile, err := getConfigFile(composefile, stdin) if err != nil { return details, err } @@ -150,15 +159,24 @@ func buildEnvironment(env []string) (map[string]string, error) { return result, nil } -func getConfigFile(filename string) (*composetypes.ConfigFile, error) { - bytes, err := ioutil.ReadFile(filename) +func getConfigFile(filename string, stdin io.Reader) (*composetypes.ConfigFile, error) { + var bytes []byte + var err error + + if filename == "-" { + bytes, err = ioutil.ReadAll(stdin) + } else { + bytes, err = ioutil.ReadFile(filename) + } if err != nil { return nil, err } + config, err := loader.ParseYAML(bytes) if err != nil { return nil, err } + return &composetypes.ConfigFile{ Filename: filename, Config: config, diff --git a/cli/command/stack/deploy_composefile_test.go b/cli/command/stack/deploy_composefile_test.go index 8d09ab056c..2e6906f69d 100644 --- a/cli/command/stack/deploy_composefile_test.go +++ b/cli/command/stack/deploy_composefile_test.go @@ -3,6 +3,7 @@ package stack import ( "os" "path/filepath" + "strings" "testing" "github.com/docker/cli/cli/internal/test/network" @@ -25,10 +26,28 @@ services: file := fs.NewFile(t, "test-get-config-details", fs.WithContent(content)) defer file.Remove() - details, err := getConfigDetails(file.Path()) + details, err := getConfigDetails(file.Path(), nil) require.NoError(t, err) assert.Equal(t, filepath.Dir(file.Path()), details.WorkingDir) - assert.Len(t, details.ConfigFiles, 1) + require.Len(t, details.ConfigFiles, 1) + assert.Equal(t, "3.0", details.ConfigFiles[0].Config["version"]) + assert.Len(t, details.Environment, len(os.Environ())) +} + +func TestGetConfigDetailsStdin(t *testing.T) { + content := ` +version: "3.0" +services: + foo: + image: alpine:3.5 +` + details, err := getConfigDetails("-", strings.NewReader(content)) + require.NoError(t, err) + cwd, err := os.Getwd() + require.NoError(t, err) + assert.Equal(t, cwd, details.WorkingDir) + require.Len(t, details.ConfigFiles, 1) + assert.Equal(t, "3.0", details.ConfigFiles[0].Config["version"]) assert.Len(t, details.Environment, len(os.Environ())) } diff --git a/docs/reference/commandline/stack_deploy.md b/docs/reference/commandline/stack_deploy.md index dd9a4cd65c..15feaa8519 100644 --- a/docs/reference/commandline/stack_deploy.md +++ b/docs/reference/commandline/stack_deploy.md @@ -57,6 +57,23 @@ Creating service vossibility_ghollector Creating service vossibility_lookupd ``` +The Compose file can also be provided as standard input with `--compose-file -`: + +```bash +$ cat docker-compose.yml | docker stack deploy --compose-file - vossibility + +Ignoring unsupported options: links + +Creating network vossibility_vossibility +Creating network vossibility_default +Creating service vossibility_nsqd +Creating service vossibility_logstash +Creating service vossibility_elasticsearch +Creating service vossibility_kibana +Creating service vossibility_ghollector +Creating service vossibility_lookupd +``` + Only a single Compose file is accepted. If your configuration is split between multiple Compose files, e.g. a base configuration and environment-specific overrides, you can combine these by passing them to `docker-compose config` with the `-f` option