go program gen: prompt array conversion, unused range vars, id handling (#4884)

This commit is contained in:
Evan Boyle 2020-06-24 11:07:26 -07:00 committed by GitHub
parent 6bad3a3620
commit 31770c3300
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 119 additions and 10 deletions

View file

@ -3,6 +3,9 @@ CHANGELOG
## HEAD (Unreleased)
- Go program gen: prompt array conversion, unused range vars, id handling
[#4884](https://github.com/pulumi/pulumi/pull/4884)
- Go program gen handling for prompt optional primitives
[#4875](https://github.com/pulumi/pulumi/pull/4875)

View file

@ -29,6 +29,7 @@ type generator struct {
splatSpiller *splatSpiller
optionalSpiller *optionalSpiller
scopeTraversalRoots codegen.StringSet
arrayHelpers map[string]*promptToInputArrayHelper
}
func GenerateProgram(program *hcl2.Program) (map[string][]byte, hcl.Diagnostics, error) {
@ -50,6 +51,7 @@ func GenerateProgram(program *hcl2.Program) (map[string][]byte, hcl.Diagnostics,
splatSpiller: &splatSpiller{},
optionalSpiller: &optionalSpiller{},
scopeTraversalRoots: codegen.NewStringSet(),
arrayHelpers: make(map[string]*promptToInputArrayHelper),
}
g.Formatter = format.NewFormatter(g)
@ -212,6 +214,14 @@ func (g *generator) genPostamble(w io.Writer, nodes []hcl2.Node) {
g.Fprint(w, "return nil\n")
g.Fprintf(w, "})\n")
g.Fprintf(w, "}\n")
g.genHelpers(w)
}
func (g *generator) genHelpers(w io.Writer) {
for _, v := range g.arrayHelpers {
v.generateHelperMethod(w)
}
}
func (g *generator) genNode(w io.Writer, n hcl2.Node) {
@ -243,7 +253,7 @@ func (g *generator) genResource(w io.Writer, r *hcl2.Resource) {
g.genTemps(w, temps)
}
instantiate := func(varName, resourceName string) {
instantiate := func(varName, resourceName string, w io.Writer) {
if g.scopeTraversalRoots.Has(varName) || strings.HasPrefix(varName, "_") {
g.Fgenf(w, "%s, err := %s.New%s(ctx, %s, ", varName, mod, typ, resourceName)
} else {
@ -273,13 +283,24 @@ func (g *generator) genResource(w io.Writer, r *hcl2.Resource) {
g.Fgenf(w, "var %s []*%s.%s\n", resName, mod, typ)
g.Fgenf(w, "for key0, val0 := range %.v {\n", rangeExpr)
instantiate("_res", fmt.Sprintf(`fmt.Sprintf("%s-%%v", key0)`, resName))
// ahead of range statement declaration generate the resource instantiation
// to detect and removed unused k,v variables
var buf bytes.Buffer
instantiate("_res", fmt.Sprintf(`fmt.Sprintf("%s-%%v", key0)`, resName), &buf)
instantiation := buf.String()
isValUsed := strings.Contains(instantiation, "val0")
valVar := "_"
if isValUsed {
valVar = "val0"
}
g.Fgenf(w, "for key0, %s := range %.v {\n", valVar, rangeExpr)
g.Fgen(w, instantiation)
g.Fgenf(w, "%s = append(%s, _res)\n", resName, resName)
g.Fgenf(w, "}\n")
} else {
instantiate(resName, fmt.Sprintf("\"%s\"", resName))
instantiate(resName, fmt.Sprintf("%q", resName), w)
}
}
@ -357,7 +378,11 @@ func (g *generator) genTempsMultiReturn(w io.Writer, temps []interface{}, zeroVa
g.Fgenf(w, "}\n")
case *splatTemp:
argTyp := g.argumentTypeName(t.Value.Each, t.Value.Each.Type(), false)
g.Fgenf(w, "var %s []%s\n", t.Name, argTyp)
if strings.Contains(argTyp, ".") {
g.Fgenf(w, "var %s %sArray\n", t.Name, argTyp)
} else {
g.Fgenf(w, "var %s []%s\n", t.Name, argTyp)
}
g.Fgenf(w, "for _, val0 := range %.v {\n", t.Value.Source)
g.Fgenf(w, "%s = append(%s, %.v)\n", t.Name, t.Name, t.Value.Each)
g.Fgenf(w, "}\n")

View file

@ -436,7 +436,24 @@ func (g *generator) genScopeTraversalExpression(w io.Writer, expr *model.ScopeTr
// TODO if it's an array type, we need a lowering step to turn []string -> pulumi.StringArray
if isInput {
g.Fgenf(w, "%s(", g.argumentTypeName(expr, expr.Type(), isInput))
argType := g.argumentTypeName(expr, expr.Type(), isInput)
if strings.HasSuffix(argType, "Array") {
// use a helper to transform prompt arrays into inputty arrays
var helper *promptToInputArrayHelper
if h, ok := g.arrayHelpers[argType]; ok {
helper = h
} else {
// helpers are emitted at the end in the postamble step
helper = &promptToInputArrayHelper{
destType: argType,
}
g.arrayHelpers[argType] = helper
}
g.Fgenf(w, "%s(", helper.getFnName())
} else {
g.Fgenf(w, "%s(", g.argumentTypeName(expr, expr.Type(), isInput))
}
}
// TODO: this isn't exhaustively correct as "range" could be a legit var name

View file

@ -119,6 +119,7 @@ func newTestGenerator(t *testing.T, testFile string) *generator {
splatSpiller: &splatSpiller{},
optionalSpiller: &optionalSpiller{},
scopeTraversalRoots: codegen.NewStringSet(),
arrayHelpers: make(map[string]*promptToInputArrayHelper),
}
g.Formatter = format.NewFormatter(g)
return g

View file

@ -0,0 +1,56 @@
package gen
import (
"fmt"
"io"
"strings"
"github.com/pulumi/pulumi/sdk/v2/go/common/util/contract"
)
type promptToInputArrayHelper struct {
destType string
}
var primitives = map[string]string{
"String": "string",
"Bool": "bool",
"Int": "int",
"Int64": "int64",
"Float64": "float64",
}
func (p *promptToInputArrayHelper) generateHelperMethod(w io.Writer) {
promptType := p.getPromptItemType()
inputType := p.getInputItemType()
fnName := p.getFnName()
fmt.Fprintf(w, "func %s(arr []%s) %s {\n", fnName, promptType, p.destType)
fmt.Fprintf(w, "var pulumiArr %s\n", p.destType)
fmt.Fprintf(w, "for _, v := range arr {\n")
fmt.Fprintf(w, "pulumiArr = append(pulumiArr, %s(v))\n", inputType)
fmt.Fprintf(w, "}\n")
fmt.Fprintf(w, "return pulumiArr\n")
fmt.Fprintf(w, "}\n")
}
func (p *promptToInputArrayHelper) getFnName() string {
parts := strings.Split(p.destType, ".")
contract.Assertf(len(parts) == 2, "promptToInputArrayHelper destType expected to have two parts.")
return fmt.Sprintf("to%s%s", Title(parts[0]), Title(parts[1]))
}
func (p *promptToInputArrayHelper) getPromptItemType() string {
inputType := p.getInputItemType()
parts := strings.Split(inputType, ".")
contract.Assertf(len(parts) == 2, "promptToInputArrayHelper destType expected to have two parts.")
typ := parts[1]
if t, ok := primitives[typ]; ok {
return t
}
return typ
}
func (p *promptToInputArrayHelper) getInputItemType() string {
return strings.TrimSuffix(p.destType, "Array")
}

View file

@ -71,7 +71,7 @@ func main() {
vpcSubnet = append(vpcSubnet, _res)
}
var rta []*ec2.RouteTableAssociation
for key0, val0 := range zones.Names {
for key0, _ := range zones.Names {
_res, err := ec2.NewRouteTableAssociation(ctx, fmt.Sprintf("rta-%v", key0), &ec2.RouteTableAssociationArgs{
RouteTableId: eksRouteTable.ID(),
SubnetId: vpcSubnet[key0].ID(),
@ -81,7 +81,7 @@ func main() {
}
rta = append(rta, _res)
}
var splat0 []pulumi.String
var splat0 pulumi.StringArray
for _, val0 := range vpcSubnet {
splat0 = append(splat0, val0.ID())
}

View file

@ -86,7 +86,7 @@ func main() {
return err
}
webLoadBalancer, err := elasticloadbalancingv2.NewLoadBalancer(ctx, "webLoadBalancer", &elasticloadbalancingv2.LoadBalancerArgs{
Subnets: pulumi.StringArray(subnets.Ids),
Subnets: toPulumiStringArray(subnets.Ids),
SecurityGroups: pulumi.StringArray{
webSecurityGroup.ID(),
},
@ -154,7 +154,7 @@ func main() {
TaskDefinition: appTask.Arn,
NetworkConfiguration: &ecs.ServiceNetworkConfigurationArgs{
AssignPublicIp: pulumi.Bool(true),
Subnets: pulumi.StringArray(subnets.Ids),
Subnets: toPulumiStringArray(subnets.Ids),
SecurityGroups: pulumi.StringArray{
webSecurityGroup.ID(),
},
@ -174,3 +174,10 @@ func main() {
return nil
})
}
func toPulumiStringArray(arr []string) pulumi.StringArray {
var pulumiArr pulumi.StringArray
for _, v := range arr {
pulumiArr = append(pulumiArr, pulumi.String(v))
}
return pulumiArr
}