convert: do not escape $ into $$ when using the --no-interpolate option (#9703)

Signed-off-by: Lucas Berg <root.lucasberg@gmail.com>
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
Co-authored-by: Ulysses Souza <ulyssessouza@gmail.com>
This commit is contained in:
Lucas Berg 2022-09-08 22:25:23 +02:00 committed by GitHub
parent 88df5ede42
commit 7a8d157871
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 44 additions and 21 deletions

View File

@ -18,6 +18,7 @@ package compose
import ( import (
"bufio" "bufio"
"bytes"
"context" "context"
"fmt" "fmt"
"io" "io"
@ -112,7 +113,7 @@ func convertCommand(p *projectOptions, backend api.Service) *cobra.Command {
} }
func runConvert(ctx context.Context, backend api.Service, opts convertOptions, services []string) error { func runConvert(ctx context.Context, backend api.Service, opts convertOptions, services []string) error {
var json []byte var content []byte
project, err := opts.toProject(services, project, err := opts.toProject(services,
cli.WithInterpolation(!opts.noInterpolate), cli.WithInterpolation(!opts.noInterpolate),
cli.WithResolvedPaths(true), cli.WithResolvedPaths(true),
@ -136,7 +137,7 @@ func runConvert(ctx context.Context, backend api.Service, opts convertOptions, s
} }
} }
json, err = backend.Convert(ctx, project, api.ConvertOptions{ content, err = backend.Convert(ctx, project, api.ConvertOptions{
Format: opts.Format, Format: opts.Format,
Output: opts.Output, Output: opts.Output,
}) })
@ -144,19 +145,23 @@ func runConvert(ctx context.Context, backend api.Service, opts convertOptions, s
return err return err
} }
if !opts.noInterpolate {
content = escapeDollarSign(content)
}
if opts.quiet { if opts.quiet {
return nil return nil
} }
var out io.Writer = os.Stdout var out io.Writer = os.Stdout
if opts.Output != "" && len(json) > 0 { if opts.Output != "" && len(content) > 0 {
file, err := os.Create(opts.Output) file, err := os.Create(opts.Output)
if err != nil { if err != nil {
return err return err
} }
out = bufio.NewWriter(file) out = bufio.NewWriter(file)
} }
_, err = fmt.Fprint(out, string(json)) _, err = fmt.Fprint(out, string(content))
return err return err
} }
@ -237,3 +242,9 @@ func runConfigImages(opts convertOptions, services []string) error {
} }
return nil return nil
} }
func escapeDollarSign(marshal []byte) []byte {
dollar := []byte{'$'}
escDollar := []byte{'$', '$'}
return bytes.ReplaceAll(marshal, dollar, escDollar)
}

View File

@ -17,7 +17,6 @@
package compose package compose
import ( import (
"bytes"
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
@ -95,28 +94,14 @@ func getContainerNameWithoutProject(c moby.Container) string {
func (s *composeService) Convert(ctx context.Context, project *types.Project, options api.ConvertOptions) ([]byte, error) { func (s *composeService) Convert(ctx context.Context, project *types.Project, options api.ConvertOptions) ([]byte, error) {
switch options.Format { switch options.Format {
case "json": case "json":
marshal, err := json.MarshalIndent(project, "", " ") return json.MarshalIndent(project, "", " ")
if err != nil {
return nil, err
}
return escapeDollarSign(marshal), nil
case "yaml": case "yaml":
marshal, err := yaml.Marshal(project) return yaml.Marshal(project)
if err != nil {
return nil, err
}
return escapeDollarSign(marshal), nil
default: default:
return nil, fmt.Errorf("unsupported format %q", options) return nil, fmt.Errorf("unsupported format %q", options)
} }
} }
func escapeDollarSign(marshal []byte) []byte {
dollar := []byte{'$'}
escDollar := []byte{'$', '$'}
return bytes.ReplaceAll(marshal, dollar, escDollar)
}
// projectFromName builds a types.Project based on actual resources with compose labels set // projectFromName builds a types.Project based on actual resources with compose labels set
func (s *composeService) projectFromName(containers Containers, projectName string, services ...string) (*types.Project, error) { func (s *composeService) projectFromName(containers Containers, projectName string, services ...string) (*types.Project, error) {
project := &types.Project{ project := &types.Project{

View File

@ -234,3 +234,25 @@ networks:
name: compose-e2e-convert_default`, filepath.Join(wd, "fixtures", "simple-build-test", "nginx-build")), ExitCode: 0}) name: compose-e2e-convert_default`, filepath.Join(wd, "fixtures", "simple-build-test", "nginx-build")), ExitCode: 0})
}) })
} }
func TestConvertInterpolate(t *testing.T) {
const projectName = "compose-e2e-convert-interpolate"
c := NewParallelCLI(t)
wd, err := os.Getwd()
assert.NilError(t, err)
t.Run("convert", func(t *testing.T) {
res := c.RunDockerComposeCmd(t, "-f", "./fixtures/simple-build-test/compose-interpolate.yaml", "-p", projectName, "convert", "--no-interpolate")
res.Assert(t, icmd.Expected{Out: fmt.Sprintf(`services:
nginx:
build:
context: %s
dockerfile: ${MYVAR}
networks:
default: null
networks:
default:
name: compose-e2e-convert-interpolate_default`, filepath.Join(wd, "fixtures", "simple-build-test", "nginx-build")), ExitCode: 0})
})
}

View File

@ -0,0 +1,5 @@
services:
nginx:
build:
context: nginx-build
dockerfile: ${MYVAR}