Skip to content

Commit

Permalink
fix(codegen/go): Use raw string literals for multiline-strings
Browse files Browse the repository at this point in the history
We already have logic in place to generate mutliline strings with
backticks if they meet certain conditions in genTemplateExpression.
However, the logic came into effect only if the string was complex
enough to warrant use of `Sprintf`
because the function short circuits to just printing a string literal
if the string doesn't need a `Sprintf`.

This changes genStringLiteral to be responsible for the decision
of whether the string warrants backticks or not,
retaining the prior conditions on whether the string would benefit
from being split across multiple lines.

Resolves #12358
  • Loading branch information
abhinav committed Jun 22, 2023
1 parent e8b7a9b commit da184df
Show file tree
Hide file tree
Showing 8 changed files with 165 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
changes:
- type: fix
scope: programgen/go
description: Use raw string literals for long, multi-line strings.
28 changes: 19 additions & 9 deletions pkg/codegen/go/gen_program_expressions.go
Original file line number Diff line number Diff line change
Expand Up @@ -448,10 +448,10 @@ func (g *generator) genLiteralValueExpression(w io.Writer, expr *model.LiteralVa
strVal := expr.Value.AsString()
if isPulumiType {
g.Fgenf(w, "%s(", argTypeName)
g.genStringLiteral(w, strVal)
g.genStringLiteral(w, strVal, true /* allow raw */)
g.Fgenf(w, ")")
} else {
g.genStringLiteral(w, strVal)
g.genStringLiteral(w, strVal, true /* allow raw */)
}
default:
contract.Failf("unexpected opaque type in GenLiteralValueExpression: %v (%v)", destType,
Expand Down Expand Up @@ -726,12 +726,7 @@ func (g *generator) genTemplateExpression(w io.Writer, expr *model.TemplateExpre
g.Fgenf(args, ", %.v", v)
}
g.Fgenf(w, "fmt.Sprintf(")
str := fmtStr.String()
if canBeRaw && len(str) > 50 && strings.Count(str, "\n") > 5 {
fmt.Fprintf(w, "`%s`", str)
} else {
g.genStringLiteral(w, fmtStr.String())
}
g.genStringLiteral(w, fmtStr.String(), canBeRaw)
_, err := args.WriteTo(w)
contract.AssertNoErrorf(err, "Failed to write arguments")
g.Fgenf(w, ")")
Expand Down Expand Up @@ -1113,7 +1108,22 @@ func (g *generator) rewriteThenForAllApply(
return then, typeConvDecls
}

func (g *generator) genStringLiteral(w io.Writer, v string) {
// Writes a Go string literal.
// The literal will be a raw string literal if allowRaw is true
// and the string is long enough to benefit from it.
func (g *generator) genStringLiteral(w io.Writer, v string, allowRaw bool) {
// If the string is longer than 50 characters,
// contains at least 5 newlines,
// and does not contain a backtick,
// use a backtick string literal for readability.
canBeRaw := len(v) > 50 &&
strings.Count(v, "\n") >= 5 &&
!strings.Contains(v, "`")
if allowRaw && canBeRaw {
fmt.Fprintf(w, "`%s`", v)
return
}

g.Fgen(w, "\"")
g.Fgen(w, g.escapeString(v))
g.Fgen(w, "\"")
Expand Down
4 changes: 4 additions & 0 deletions pkg/codegen/testing/test/program_driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,10 @@ var PulumiPulumiProgramTests = []ProgramTest{
Directory: "retain-on-delete",
Description: "Generate RetainOnDelete option",
},
{
Directory: "multiline-string",
Description: "Multiline string literals",
},
{
Directory: "throw-not-implemented",
Description: "Function notImplemented is compiled to a runtime error at call-site",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Random = Pulumi.Random;

return await Deployment.RunAsync(() =>
{
var foo = new Random.RandomShuffle("foo", new()
{
Inputs = new[]
{
@"just one
newline",
@"foo
bar
baz
qux
quux
qux",
@"{
""a"": 1,
""b"": 2,
""c"": [
""foo"",
""bar"",
""baz"",
""qux"",
""quux""
]
}
",
},
});
});

Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package main

import (
"github.com/pulumi/pulumi-random/sdk/v4/go/random"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := random.NewRandomShuffle(ctx, "foo", &random.RandomShuffleArgs{
Inputs: pulumi.StringArray{
pulumi.String("just one\nnewline"),
pulumi.String("foo\nbar\nbaz\nqux\nquux\nqux"),
pulumi.String(`{
"a": 1,
"b": 2,
"c": [
"foo",
"bar",
"baz",
"qux",
"quux"
]
}
`),
},
})
if err != nil {
return err
}
return nil
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
resource foo "random:index/randomShuffle:RandomShuffle" {
inputs = [
"just one\nnewline",
"foo\nbar\nbaz\nqux\nquux\nqux",
<<-EOT
{
"a": 1,
"b": 2,
"c": [
"foo",
"bar",
"baz",
"qux",
"quux"
]
}
EOT
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import * as pulumi from "@pulumi/pulumi";
import * as random from "@pulumi/random";

const foo = new random.RandomShuffle("foo", {inputs: [
`just one
newline`,
`foo
bar
baz
qux
quux
qux`,
`{
"a": 1,
"b": 2,
"c": [
"foo",
"bar",
"baz",
"qux",
"quux"
]
}
`,
]});
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import pulumi
import pulumi_random as random

foo = random.RandomShuffle("foo", inputs=[
"""just one
newline""",
"""foo
bar
baz
qux
quux
qux""",
"""{
"a": 1,
"b": 2,
"c": [
"foo",
"bar",
"baz",
"qux",
"quux"
]
}
""",
])

0 comments on commit da184df

Please sign in to comment.