[Go Program Gen] multiline strings, get/lookup disambiguation, webserver example (#4850)
This commit is contained in:
parent
08d94466db
commit
8b8170252b
|
@ -3,6 +3,9 @@ CHANGELOG
|
|||
|
||||
## HEAD (Unreleased)
|
||||
|
||||
- Go program gen improvements (multiline strings, get/lookup disambiguation, invoke improvements)
|
||||
[#4850](https://github.com/pulumi/pulumi/pull/4850)
|
||||
|
||||
- Go program gen improvements (splat, all, index, traversal, range)
|
||||
[#4831](https://github.com/pulumi/pulumi/pull/4831)
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/pulumi/pulumi/pkg/v2/codegen/hcl2"
|
||||
"github.com/pulumi/pulumi/pkg/v2/codegen/hcl2/model"
|
||||
"github.com/pulumi/pulumi/pkg/v2/codegen/hcl2/model/format"
|
||||
"github.com/pulumi/pulumi/pkg/v2/codegen/schema"
|
||||
"github.com/pulumi/pulumi/sdk/v2/go/common/util/contract"
|
||||
)
|
||||
|
||||
|
@ -20,6 +21,7 @@ type generator struct {
|
|||
// The formatter to use when generating code.
|
||||
*format.Formatter
|
||||
program *hcl2.Program
|
||||
contexts map[string]map[string]*pkgContext
|
||||
diagnostics hcl.Diagnostics
|
||||
jsonTempSpiller *jsonSpiller
|
||||
ternaryTempSpiller *tempSpiller
|
||||
|
@ -32,8 +34,15 @@ func GenerateProgram(program *hcl2.Program) (map[string][]byte, hcl.Diagnostics,
|
|||
// Linearize the nodes into an order appropriate for procedural code generation.
|
||||
nodes := hcl2.Linearize(program)
|
||||
|
||||
contexts := make(map[string]map[string]*pkgContext)
|
||||
|
||||
for _, pkg := range program.Packages() {
|
||||
contexts[pkg.Name] = getPackages("tool", pkg)
|
||||
}
|
||||
|
||||
g := &generator{
|
||||
program: program,
|
||||
contexts: contexts,
|
||||
jsonTempSpiller: &jsonSpiller{},
|
||||
ternaryTempSpiller: &tempSpiller{},
|
||||
readDirTempSpiller: &readDirSpiller{},
|
||||
|
@ -68,6 +77,15 @@ func GenerateProgram(program *hcl2.Program) (map[string][]byte, hcl.Diagnostics,
|
|||
return files, g.diagnostics, nil
|
||||
}
|
||||
|
||||
func getPackages(tool string, pkg *schema.Package) map[string]*pkgContext {
|
||||
if err := pkg.ImportLanguages(map[string]schema.Language{"go": Importer}); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
goInfo, _ := pkg.Language["go"].(GoPackageInfo)
|
||||
return generatePackageContextMap(tool, pkg, goInfo)
|
||||
}
|
||||
|
||||
func (g *generator) collectScopeRoots(n hcl2.Node) {
|
||||
diags := n.VisitExpressions(nil, func(n model.Expression) (model.Expression, hcl.Diagnostics) {
|
||||
if st, ok := n.(*model.ScopeTraversalExpression); ok {
|
||||
|
@ -120,15 +138,54 @@ func (g *generator) collectImports(w io.Writer, program *hcl2.Program) (codegen.
|
|||
panic(errors.Errorf("could not find package information for resource with type token:\n\n%s", r.Token))
|
||||
}
|
||||
|
||||
vPath := fmt.Sprintf("/v%d", version)
|
||||
if version <= 1 {
|
||||
vPath = ""
|
||||
var vPath string
|
||||
if version > 1 {
|
||||
vPath = fmt.Sprintf("/v%d", version)
|
||||
}
|
||||
|
||||
pulumiImports.Add(fmt.Sprintf("github.com/pulumi/pulumi-%s/sdk%s/go/%s/%s", pkg, vPath, pkg, mod))
|
||||
}
|
||||
|
||||
diags := n.VisitExpressions(nil, func(n model.Expression) (model.Expression, hcl.Diagnostics) {
|
||||
if call, ok := n.(*model.FunctionCallExpression); ok {
|
||||
if call.Name == hcl2.Invoke {
|
||||
tokenArg := call.Args[0]
|
||||
token := tokenArg.(*model.TemplateExpression).Parts[0].(*model.LiteralValueExpression).Value.AsString()
|
||||
tokenRange := tokenArg.SyntaxNode().Range()
|
||||
pkg, mod, _, diagnostics := hcl2.DecomposeToken(token, tokenRange)
|
||||
|
||||
contract.Assert(len(diagnostics) == 0)
|
||||
|
||||
version := -1
|
||||
for _, p := range program.Packages() {
|
||||
if p.Name == pkg {
|
||||
version = int(p.Version.Major)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if version == -1 {
|
||||
panic(errors.Errorf("could not find package information for resource with type token:\n\n%s", token))
|
||||
}
|
||||
|
||||
var vPath string
|
||||
if version > 1 {
|
||||
vPath = fmt.Sprintf("/v%d", version)
|
||||
}
|
||||
|
||||
// namespaceless invokes "aws:index:..."
|
||||
if mod == "" {
|
||||
pulumiImports.Add(fmt.Sprintf("github.com/pulumi/pulumi-%s/sdk%s/go/%s", pkg, vPath, pkg))
|
||||
} else {
|
||||
pulumiImports.Add(fmt.Sprintf("github.com/pulumi/pulumi-%s/sdk%s/go/%s/%s", pkg, vPath, pkg, mod))
|
||||
}
|
||||
}
|
||||
}
|
||||
return n, nil
|
||||
})
|
||||
contract.Assert(len(diags) == 0)
|
||||
|
||||
diags = n.VisitExpressions(nil, func(n model.Expression) (model.Expression, hcl.Diagnostics) {
|
||||
if call, ok := n.(*model.FunctionCallExpression); ok {
|
||||
for _, fnPkg := range g.genFunctionPackages(call) {
|
||||
stdImports.Add(fnPkg)
|
||||
|
@ -260,7 +317,7 @@ func (g *generator) genTempsMultiReturn(w io.Writer, temps []interface{}, zeroVa
|
|||
case *ternaryTemp:
|
||||
// TODO derive from ambient context
|
||||
isInput := false
|
||||
g.Fgenf(w, "var %s %s\n", t.Name, argumentTypeName(t.Value.TrueResult, t.Type(), isInput))
|
||||
g.Fgenf(w, "var %s %s\n", t.Name, g.argumentTypeName(t.Value.TrueResult, t.Type(), isInput))
|
||||
g.Fgenf(w, "if %.v {\n", t.Value.Condition)
|
||||
g.Fgenf(w, "%s = %.v\n", t.Name, t.Value.TrueResult)
|
||||
g.Fgenf(w, "} else {\n")
|
||||
|
@ -297,7 +354,7 @@ func (g *generator) genTempsMultiReturn(w io.Writer, temps []interface{}, zeroVa
|
|||
g.Fgenf(w, "%s[%s] = %s.Name()\n", namesVar, iVar, valVar)
|
||||
g.Fgenf(w, "}\n")
|
||||
case *splatTemp:
|
||||
argTyp := argumentTypeName(t.Value.Each, t.Value.Each.Type(), false)
|
||||
argTyp := g.argumentTypeName(t.Value.Each, t.Value.Each.Type(), false)
|
||||
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)
|
||||
|
@ -331,3 +388,30 @@ func (g *generator) genLocalVariable(w io.Writer, v *hcl2.LocalVariable) {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
// nolint: lll
|
||||
// uselookupInvokeForm takes a token for an invoke and determines whether to use the
|
||||
// .Get or .Lookup form. The Go SDK has collisions in .Get methods that require renaming.
|
||||
// For instance, gen.go creates a resource getter for AWS VPCs that collides with a function:
|
||||
// GetVPC resource getter: https://github.com/pulumi/pulumi-aws/blob/7835df354694e2f9f23371602a9febebc6b45be8/sdk/go/aws/ec2/getVpc.go#L15
|
||||
// LookupVPC function: https://github.com/pulumi/pulumi-aws/blob/7835df354694e2f9f23371602a9febebc6b45be8/sdk/go/aws/ec2/getVpc.go#L15
|
||||
// Given that the naming here is not consisten, we must reverse the process from gen.go.
|
||||
func (g *generator) useLookupInvokeForm(token string) bool {
|
||||
pkg, module, member, _ := hcl2.DecomposeToken(token, *new(hcl.Range))
|
||||
modSplit := strings.Split(module, "/")
|
||||
mod := modSplit[0]
|
||||
if mod == "index" {
|
||||
mod = ""
|
||||
}
|
||||
fn := Title(member)
|
||||
if len(modSplit) >= 2 {
|
||||
fn = Title(modSplit[1])
|
||||
}
|
||||
fnLookup := "Lookup" + fn[3:]
|
||||
pkgContext := g.contexts[pkg][mod]
|
||||
if pkgContext.names.has(fnLookup) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -66,12 +66,12 @@ func (g *generator) GenAnonymousFunctionExpression(w io.Writer, expr *model.Anon
|
|||
leadingSep := ""
|
||||
for _, param := range expr.Signature.Parameters {
|
||||
isInput := isInputty(param.Type)
|
||||
g.Fgenf(w, "%s%s %s", leadingSep, param.Name, argumentTypeName(nil, param.Type, isInput))
|
||||
g.Fgenf(w, "%s%s %s", leadingSep, param.Name, g.argumentTypeName(nil, param.Type, isInput))
|
||||
leadingSep = ", "
|
||||
}
|
||||
|
||||
isInput := isInputty(expr.Signature.ReturnType)
|
||||
retType := argumentTypeName(nil, expr.Signature.ReturnType, isInput)
|
||||
retType := g.argumentTypeName(nil, expr.Signature.ReturnType, isInput)
|
||||
g.Fgenf(w, ") (%s, error) {\n", retType)
|
||||
|
||||
body, temps := g.lowerExpression(expr.Body, expr.Signature.ReturnType, isInput)
|
||||
|
@ -144,8 +144,10 @@ func (g *generator) GenFunctionCallExpression(w io.Writer, expr *model.FunctionC
|
|||
g.genRelativeTraversalExpression(w, arg, isInput)
|
||||
case *model.ScopeTraversalExpression:
|
||||
g.genScopeTraversalExpression(w, arg, isInput)
|
||||
case *model.ObjectConsExpression:
|
||||
g.genObjectConsExpression(w, arg, expr.Type(), isInput)
|
||||
default:
|
||||
argType := argumentTypeName(arg, arg.Type(), isInput)
|
||||
argType := g.argumentTypeName(arg, arg.Type(), isInput)
|
||||
g.Fgenf(w, "%s(%v", argType, arg)
|
||||
g.Fgenf(w, ")")
|
||||
}
|
||||
|
@ -154,7 +156,8 @@ func (g *generator) GenFunctionCallExpression(w io.Writer, expr *model.FunctionC
|
|||
case *model.TupleConsExpression:
|
||||
g.genTupleConsExpression(w, arg, expr.Type())
|
||||
case *model.ObjectConsExpression:
|
||||
g.genObjectConsExpression(w, arg, expr.Type())
|
||||
isInput := false
|
||||
g.genObjectConsExpression(w, arg, expr.Type(), isInput)
|
||||
case *model.LiteralValueExpression:
|
||||
g.genLiteralValueExpression(w, arg, expr.Type())
|
||||
default:
|
||||
|
@ -188,7 +191,7 @@ func (g *generator) GenFunctionCallExpression(w io.Writer, expr *model.FunctionC
|
|||
case "fileAsset":
|
||||
g.Fgenf(w, "pulumi.NewFileAsset(%.v)", expr.Args[0])
|
||||
case hcl2.Invoke:
|
||||
pkg, module, fn, diags := functionName(expr.Args[0])
|
||||
pkg, module, fn, diags := g.functionName(expr.Args[0])
|
||||
contract.Assert(len(diags) == 0)
|
||||
if module == "" {
|
||||
module = pkg
|
||||
|
@ -240,7 +243,7 @@ func (g *generator) GenLiteralValueExpression(w io.Writer, expr *model.LiteralVa
|
|||
}
|
||||
|
||||
func (g *generator) genLiteralValueExpression(w io.Writer, expr *model.LiteralValueExpression, destType model.Type) {
|
||||
argTypeName := argumentTypeName(expr, destType, false)
|
||||
argTypeName := g.argumentTypeName(expr, destType, false)
|
||||
isPulumiType := strings.HasPrefix(argTypeName, "pulumi.")
|
||||
|
||||
switch destType := destType.(type) {
|
||||
|
@ -298,19 +301,25 @@ func (g *generator) genLiteralValueExpression(w io.Writer, expr *model.LiteralVa
|
|||
}
|
||||
|
||||
func (g *generator) GenObjectConsExpression(w io.Writer, expr *model.ObjectConsExpression) {
|
||||
g.genObjectConsExpression(w, expr, expr.Type())
|
||||
isInput := false
|
||||
g.genObjectConsExpression(w, expr, expr.Type(), isInput)
|
||||
}
|
||||
|
||||
func (g *generator) genObjectConsExpression(w io.Writer, expr *model.ObjectConsExpression, destType model.Type) {
|
||||
func (g *generator) genObjectConsExpression(
|
||||
w io.Writer,
|
||||
expr *model.ObjectConsExpression,
|
||||
destType model.Type,
|
||||
isInput bool,
|
||||
) {
|
||||
if len(expr.Items) > 0 {
|
||||
var temps []interface{}
|
||||
isInput := isInputty(destType)
|
||||
typeName := argumentTypeName(expr, destType, isInput)
|
||||
isInput = isInput || isInputty(destType)
|
||||
typeName := g.argumentTypeName(expr, destType, isInput)
|
||||
if strings.HasSuffix(typeName, "Args") {
|
||||
isInput = true
|
||||
}
|
||||
// invokes are not inputty
|
||||
if strings.Contains(typeName, ".Lookup") {
|
||||
if strings.Contains(typeName, ".Lookup") || strings.Contains(typeName, ".Get") {
|
||||
isInput = false
|
||||
}
|
||||
isMap := strings.HasPrefix(typeName, "map[")
|
||||
|
@ -330,7 +339,7 @@ func (g *generator) genObjectConsExpression(w io.Writer, expr *model.ObjectConsE
|
|||
}
|
||||
g.genTemps(w, temps)
|
||||
|
||||
if isMap {
|
||||
if isMap || !strings.HasSuffix(typeName, "Args") {
|
||||
g.Fgenf(w, "%s", typeName)
|
||||
} else {
|
||||
g.Fgenf(w, "&%s", typeName)
|
||||
|
@ -339,7 +348,7 @@ func (g *generator) genObjectConsExpression(w io.Writer, expr *model.ObjectConsE
|
|||
|
||||
for _, item := range expr.Items {
|
||||
if lit, ok := g.literalKey(item.Key); ok {
|
||||
if isMap {
|
||||
if isMap || strings.HasSuffix(typeName, "Map") {
|
||||
g.Fgenf(w, "\"%s\"", lit)
|
||||
} else {
|
||||
g.Fgenf(w, "%s", Title(lit))
|
||||
|
@ -366,7 +375,7 @@ func (g *generator) genRelativeTraversalExpression(w io.Writer, expr *model.Rela
|
|||
isInput = false
|
||||
}
|
||||
if isInput {
|
||||
g.Fgenf(w, "%s(", argumentTypeName(expr, expr.Type(), isInput))
|
||||
g.Fgenf(w, "%s(", g.argumentTypeName(expr, expr.Type(), isInput))
|
||||
}
|
||||
g.GenRelativeTraversalExpression(w, expr)
|
||||
if isInput {
|
||||
|
@ -415,7 +424,7 @@ 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(", argumentTypeName(expr, expr.Type(), isInput))
|
||||
g.Fgenf(w, "%s(", g.argumentTypeName(expr, expr.Type(), isInput))
|
||||
}
|
||||
|
||||
// TODO: this isn't exhaustively correct as "range" could be a legit var name
|
||||
|
@ -488,7 +497,7 @@ func (g *generator) genTupleConsExpression(w io.Writer, expr *model.TupleConsExp
|
|||
expr.Expressions[i] = item
|
||||
}
|
||||
g.genTemps(w, temps)
|
||||
argType := argumentTypeName(expr, destType, isInput)
|
||||
argType := g.argumentTypeName(expr, destType, isInput)
|
||||
g.Fgenf(w, "%s{\n", argType)
|
||||
switch len(expr.Expressions) {
|
||||
case 0:
|
||||
|
@ -514,7 +523,7 @@ func (g *generator) GenUnaryOpExpression(w io.Writer, expr *model.UnaryOpExpress
|
|||
}
|
||||
|
||||
// argumentTypeName computes the go type for the given expression and model type.
|
||||
func argumentTypeName(expr model.Expression, destType model.Type, isInput bool) string {
|
||||
func (g *generator) argumentTypeName(expr model.Expression, destType model.Type, isInput bool) string {
|
||||
var tokenRange hcl.Range
|
||||
if expr != nil {
|
||||
node := expr.SyntaxNode()
|
||||
|
@ -526,22 +535,39 @@ func argumentTypeName(expr model.Expression, destType model.Type, isInput bool)
|
|||
switch schemaType := schemaType.(type) {
|
||||
case *schema.ArrayType:
|
||||
token := schemaType.ElementType.(*schema.ObjectType).Token
|
||||
_, module, member, diags := hcl2.DecomposeToken(token, tokenRange)
|
||||
pkg, module, member, diags := hcl2.DecomposeToken(token, tokenRange)
|
||||
// namespaceless invokes
|
||||
if module == "" || strings.HasPrefix(module, "/") || strings.HasPrefix(module, "index/") {
|
||||
module = pkg
|
||||
}
|
||||
importPrefix := strings.Split(module, "/")[0]
|
||||
contract.Assert(len(diags) == 0)
|
||||
fmtString := "[]%s.%s"
|
||||
if isInput {
|
||||
member = Title(member)
|
||||
if strings.HasPrefix(member, "Get") {
|
||||
if g.useLookupInvokeForm(token) {
|
||||
member = strings.Replace(member, "Get", "Lookup", 1)
|
||||
}
|
||||
return fmt.Sprintf("[]%s.%s", importPrefix, member)
|
||||
}
|
||||
fmtString = "%s.%sArray"
|
||||
}
|
||||
return fmt.Sprintf(fmtString, importPrefix, member)
|
||||
case *schema.ObjectType:
|
||||
token := schemaType.Token
|
||||
_, module, member, diags := hcl2.DecomposeToken(token, tokenRange)
|
||||
pkg, module, member, diags := hcl2.DecomposeToken(token, tokenRange)
|
||||
// namespaceless invokes
|
||||
if module == "" || strings.HasPrefix(module, "/") || strings.HasPrefix(module, "index/") {
|
||||
module = pkg
|
||||
}
|
||||
importPrefix := strings.Split(module, "/")[0]
|
||||
contract.Assert(len(diags) == 0)
|
||||
member = Title(member)
|
||||
if strings.HasPrefix(member, "Get") {
|
||||
member = strings.Replace(member, "Get", "Lookup", 1)
|
||||
if g.useLookupInvokeForm(token) {
|
||||
member = strings.Replace(member, "Get", "Lookup", 1)
|
||||
}
|
||||
return fmt.Sprintf("%s.%s", importPrefix, member)
|
||||
}
|
||||
fmtString := "%s.%s"
|
||||
|
@ -586,13 +612,13 @@ func argumentTypeName(expr model.Expression, destType model.Type, isInput bool)
|
|||
}
|
||||
return "map[string]interface{}"
|
||||
case *model.MapType:
|
||||
valType := argumentTypeName(nil, destType.ElementType, isInput)
|
||||
valType := g.argumentTypeName(nil, destType.ElementType, isInput)
|
||||
if isInput {
|
||||
return fmt.Sprintf("pulumi.%sMap", Title(valType))
|
||||
}
|
||||
return fmt.Sprintf("map[string]%s", valType)
|
||||
case *model.ListType:
|
||||
argTypeName := argumentTypeName(nil, destType.ElementType, isInput)
|
||||
argTypeName := g.argumentTypeName(nil, destType.ElementType, isInput)
|
||||
if strings.HasPrefix(argTypeName, "pulumi.") {
|
||||
return fmt.Sprintf("%sArray", argTypeName)
|
||||
}
|
||||
|
@ -613,7 +639,7 @@ func argumentTypeName(expr model.Expression, destType model.Type, isInput bool)
|
|||
}
|
||||
|
||||
if elmType != nil {
|
||||
argTypeName := argumentTypeName(nil, elmType, isInput)
|
||||
argTypeName := g.argumentTypeName(nil, elmType, isInput)
|
||||
if strings.HasPrefix(argTypeName, "pulumi.") {
|
||||
return fmt.Sprintf("%sArray", argTypeName)
|
||||
}
|
||||
|
@ -626,16 +652,16 @@ func argumentTypeName(expr model.Expression, destType model.Type, isInput bool)
|
|||
return "[]interface{}"
|
||||
case *model.OutputType:
|
||||
isInput = true
|
||||
return argumentTypeName(expr, destType.ElementType, isInput)
|
||||
return g.argumentTypeName(expr, destType.ElementType, isInput)
|
||||
case *model.UnionType:
|
||||
for _, ut := range destType.ElementTypes {
|
||||
if _, isOpaqueType := ut.(*model.OpaqueType); isOpaqueType {
|
||||
return argumentTypeName(expr, ut, isInput)
|
||||
return g.argumentTypeName(expr, ut, isInput)
|
||||
}
|
||||
}
|
||||
return "interface{}"
|
||||
case *model.PromiseType:
|
||||
return argumentTypeName(expr, destType.ElementType, isInput)
|
||||
return g.argumentTypeName(expr, destType.ElementType, isInput)
|
||||
default:
|
||||
contract.Failf("unexpected destType type %T", destType)
|
||||
}
|
||||
|
@ -737,7 +763,7 @@ func (g *generator) genApply(w io.Writer, expr *model.FunctionCallExpression) {
|
|||
applyArgs, then := hcl2.ParseApplyCall(expr)
|
||||
then = stripInputs(then).(*model.AnonymousFunctionExpression)
|
||||
isInput := false
|
||||
retType := argumentTypeName(nil, then.Signature.ReturnType, isInput)
|
||||
retType := g.argumentTypeName(nil, then.Signature.ReturnType, isInput)
|
||||
// TODO account for outputs in other namespaces like aws
|
||||
typeAssertion := fmt.Sprintf(".(%sOutput)", retType)
|
||||
if !strings.HasPrefix(retType, "pulumi.") {
|
||||
|
@ -755,23 +781,14 @@ func (g *generator) genApply(w io.Writer, expr *model.FunctionCallExpression) {
|
|||
}
|
||||
// TODO need lowering step to rewrite then argument references
|
||||
// in terms of scope traversal from all result: val[i] etc.
|
||||
g.Fgenf(w, ").Apply(%.v)%s", then, typeAssertion)
|
||||
g.Fgenf(w, ").ApplyT(%.v)%s", then, typeAssertion)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *generator) genStringLiteral(w io.Writer, v string) {
|
||||
// TODO more robust and go-specific handling of strings
|
||||
newlines := strings.Contains(v, "\n")
|
||||
if !newlines {
|
||||
// This string does not contain newlines so we'll generate a regular string literal. Quotes and backslashes
|
||||
// will be escaped in conformance with
|
||||
// https://golang.org/ref/spec#String_literals
|
||||
g.Fgen(w, "\"")
|
||||
g.Fgen(w, g.escapeString(v))
|
||||
g.Fgen(w, "\"")
|
||||
} else {
|
||||
g.genNYI(w, "TODO multiline strings")
|
||||
}
|
||||
g.Fgen(w, "\"")
|
||||
g.Fgen(w, g.escapeString(v))
|
||||
g.Fgen(w, "\"")
|
||||
}
|
||||
|
||||
func (g *generator) escapeString(v string) string {
|
||||
|
@ -780,6 +797,11 @@ func (g *generator) escapeString(v string) string {
|
|||
if c == '"' || c == '\\' {
|
||||
builder.WriteRune('\\')
|
||||
}
|
||||
if c == '\n' {
|
||||
builder.WriteRune('\\')
|
||||
builder.WriteRune('n')
|
||||
continue
|
||||
}
|
||||
builder.WriteRune(c)
|
||||
}
|
||||
return builder.String()
|
||||
|
@ -831,17 +853,16 @@ func (g *generator) literalKey(x model.Expression) (string, bool) {
|
|||
}
|
||||
|
||||
// functionName computes the go package, module, and name for the given function token.
|
||||
func functionName(tokenArg model.Expression) (string, string, string, hcl.Diagnostics) {
|
||||
func (g *generator) functionName(tokenArg model.Expression) (string, string, string, hcl.Diagnostics) {
|
||||
token := tokenArg.(*model.TemplateExpression).Parts[0].(*model.LiteralValueExpression).Value.AsString()
|
||||
tokenRange := tokenArg.SyntaxNode().Range()
|
||||
|
||||
// Compute the resource type from the Pulumi type token.
|
||||
pkg, module, member, diagnostics := hcl2.DecomposeToken(token, tokenRange)
|
||||
// GetResource -> LookupResource
|
||||
// TODO figure out how to deal with get/lookup ambiguity
|
||||
// https://github.com/pulumi/pulumi/blob/adfa8116fbf61ad328568fe4b53e32c751f30553/pkg/codegen/go/gen.go#L1171
|
||||
if strings.HasPrefix(member, "get") {
|
||||
member = strings.Replace(member, "get", "lookup", 1)
|
||||
if g.useLookupInvokeForm(token) {
|
||||
member = strings.Replace(member, "get", "lookup", 1)
|
||||
}
|
||||
}
|
||||
return pkg, strings.Replace(module, "/", ".", -1), Title(member), diagnostics
|
||||
}
|
||||
|
|
|
@ -83,6 +83,7 @@ func modifyInputs(
|
|||
for _, item := range expr.Items {
|
||||
item.Value = modifyInputs(item.Value, modf)
|
||||
}
|
||||
x = modf(x)
|
||||
case *model.TupleConsExpression:
|
||||
for i, item := range expr.Expressions {
|
||||
expr.Expressions[i] = modifyInputs(item, modf)
|
||||
|
|
|
@ -27,13 +27,6 @@ func TestGenProgram(t *testing.T) {
|
|||
if filepath.Ext(f.Name()) != ".pp" {
|
||||
continue
|
||||
}
|
||||
// TODO: include all test files
|
||||
if filepath.Base(f.Name()) != "aws-s3-logging.pp" &&
|
||||
filepath.Base(f.Name()) != "aws-s3-folder.pp" &&
|
||||
filepath.Base(f.Name()) != "aws-eks.pp" &&
|
||||
filepath.Base(f.Name()) != "aws-fargate.pp" {
|
||||
continue
|
||||
}
|
||||
|
||||
t.Run(f.Name(), func(t *testing.T) {
|
||||
path := filepath.Join(testdataPath, f.Name())
|
||||
|
|
33
pkg/codegen/internal/test/testdata/aws-eks.pp.go
vendored
33
pkg/codegen/internal/test/testdata/aws-eks.pp.go
vendored
|
@ -4,6 +4,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/pulumi/pulumi-aws/sdk/v2/go/aws"
|
||||
"github.com/pulumi/pulumi-aws/sdk/v2/go/aws/ec2"
|
||||
"github.com/pulumi/pulumi-aws/sdk/v2/go/aws/eks"
|
||||
"github.com/pulumi/pulumi-aws/sdk/v2/go/aws/iam"
|
||||
|
@ -17,8 +18,8 @@ func main() {
|
|||
InstanceTenancy: pulumi.String("default"),
|
||||
EnableDnsHostnames: pulumi.Bool(true),
|
||||
EnableDnsSupport: pulumi.Bool(true),
|
||||
Tags: map[string]interface{}{
|
||||
"Name": "pulumi-eks-vpc",
|
||||
Tags: pulumi.Map{
|
||||
"Name": pulumi.String("pulumi-eks-vpc"),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -26,8 +27,8 @@ func main() {
|
|||
}
|
||||
eksIgw, err := ec2.NewInternetGateway(ctx, "eksIgw", &ec2.InternetGatewayArgs{
|
||||
VpcId: eksVpc.ID(),
|
||||
Tags: map[string]interface{}{
|
||||
"Name": "pulumi-vpc-ig",
|
||||
Tags: pulumi.Map{
|
||||
"Name": pulumi.String("pulumi-vpc-ig"),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -41,14 +42,14 @@ func main() {
|
|||
GatewayId: eksIgw.ID(),
|
||||
},
|
||||
},
|
||||
Tags: map[string]interface{}{
|
||||
"Name": "pulumi-vpc-rt",
|
||||
Tags: pulumi.Map{
|
||||
"Name": pulumi.String("pulumi-vpc-rt"),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
zones, err := aws.LookupAvailabilityZones(ctx, nil, nil)
|
||||
zones, err := aws.GetAvailabilityZones(ctx, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -60,8 +61,8 @@ func main() {
|
|||
MapPublicIpOnLaunch: pulumi.Bool(true),
|
||||
CidrBlock: pulumi.String(fmt.Sprintf("%v%v%v", "10.100.", key0, ".0/24")),
|
||||
AvailabilityZone: pulumi.String(val0),
|
||||
Tags: map[string]interface{}{
|
||||
"Name": fmt.Sprintf("%v%v", "pulumi-sn-", val0),
|
||||
Tags: pulumi.Map{
|
||||
"Name": pulumi.String(fmt.Sprintf("%v%v", "pulumi-sn-", val0)),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -88,8 +89,8 @@ func main() {
|
|||
eksSecurityGroup, err := ec2.NewSecurityGroup(ctx, "eksSecurityGroup", &ec2.SecurityGroupArgs{
|
||||
VpcId: eksVpc.ID(),
|
||||
Description: pulumi.String("Allow all HTTP(s) traffic to EKS Cluster"),
|
||||
Tags: map[string]interface{}{
|
||||
"Name": "pulumi-cluster-sg",
|
||||
Tags: pulumi.Map{
|
||||
"Name": pulumi.String("pulumi-cluster-sg"),
|
||||
},
|
||||
Ingress: ec2.SecurityGroupIngressArray{
|
||||
&ec2.SecurityGroupIngressArgs{
|
||||
|
@ -198,8 +199,8 @@ func main() {
|
|||
}
|
||||
eksCluster, err := eks.NewCluster(ctx, "eksCluster", &eks.ClusterArgs{
|
||||
RoleArn: eksRole.Arn,
|
||||
Tags: map[string]interface{}{
|
||||
"Name": "pulumi-eks-cluster",
|
||||
Tags: pulumi.Map{
|
||||
"Name": pulumi.String("pulumi-eks-cluster"),
|
||||
},
|
||||
VpcConfig: &eks.ClusterVpcConfigArgs{
|
||||
PublicAccessCidrs: pulumi.StringArray{
|
||||
|
@ -219,8 +220,8 @@ func main() {
|
|||
NodeGroupName: pulumi.String("pulumi-eks-nodegroup"),
|
||||
NodeRoleArn: ec2Role.Arn,
|
||||
SubnetIds: subnetIds,
|
||||
Tags: map[string]interface{}{
|
||||
"Name": "pulumi-cluster-nodeGroup",
|
||||
Tags: pulumi.Map{
|
||||
"Name": pulumi.String("pulumi-cluster-nodeGroup"),
|
||||
},
|
||||
ScalingConfig: &eks.NodeGroupScalingConfigArgs{
|
||||
DesiredSize: pulumi.Int(2),
|
||||
|
@ -232,7 +233,7 @@ func main() {
|
|||
return err
|
||||
}
|
||||
ctx.Export("clusterName", eksCluster.Name)
|
||||
ctx.Export("kubeconfig", pulumi.All(eksCluster.Endpoint, eksCluster.CertificateAuthority, eksCluster.Name).Apply(func(endpoint string, certificateAuthority eks.ClusterCertificateAuthority, name string) (pulumi.String, error) {
|
||||
ctx.Export("kubeconfig", pulumi.All(eksCluster.Endpoint, eksCluster.CertificateAuthority, eksCluster.Name).ApplyT(func(endpoint string, certificateAuthority eks.ClusterCertificateAuthority, name string) (pulumi.String, error) {
|
||||
var _zero pulumi.String
|
||||
tmpJSON2, err := json.Marshal(map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
|
|
|
@ -18,7 +18,7 @@ func main() {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
subnets, err := ec2.LookupSubnetIds(ctx, &ec2.LookupSubnetIdsArgs{
|
||||
subnets, err := ec2.GetSubnetIds(ctx, &ec2.GetSubnetIdsArgs{
|
||||
VpcId: vpc.Id,
|
||||
}, nil)
|
||||
if err != nil {
|
||||
|
|
63
pkg/codegen/internal/test/testdata/aws-webserver.pp.go
vendored
Normal file
63
pkg/codegen/internal/test/testdata/aws-webserver.pp.go
vendored
Normal file
|
@ -0,0 +1,63 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pulumi/pulumi-aws/sdk/v2/go/aws"
|
||||
"github.com/pulumi/pulumi-aws/sdk/v2/go/aws/ec2"
|
||||
"github.com/pulumi/pulumi/sdk/v2/go/pulumi"
|
||||
)
|
||||
|
||||
func main() {
|
||||
pulumi.Run(func(ctx *pulumi.Context) error {
|
||||
securityGroup, err := ec2.NewSecurityGroup(ctx, "securityGroup", &ec2.SecurityGroupArgs{
|
||||
Ingress: ec2.SecurityGroupIngressArray{
|
||||
&ec2.SecurityGroupIngressArgs{
|
||||
Protocol: pulumi.String("tcp"),
|
||||
FromPort: pulumi.Int(0),
|
||||
ToPort: pulumi.Int(0),
|
||||
CidrBlocks: pulumi.StringArray{
|
||||
pulumi.String("0.0.0.0/0"),
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ami, err := aws.GetAmi(ctx, &aws.GetAmiArgs{
|
||||
Filters: []aws.GetAmiFilter{
|
||||
aws.GetAmiFilter{
|
||||
Name: "name",
|
||||
Values: []string{
|
||||
"amzn-ami-hvm-*-x86_64-ebs",
|
||||
},
|
||||
},
|
||||
},
|
||||
Owners: []string{
|
||||
"137112412989",
|
||||
},
|
||||
MostRecent: true,
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
server, err := ec2.NewInstance(ctx, "server", &ec2.InstanceArgs{
|
||||
Tags: pulumi.Map{
|
||||
"Name": pulumi.String("web-server-www"),
|
||||
},
|
||||
InstanceType: pulumi.String("t2.micro"),
|
||||
SecurityGroups: pulumi.StringArray{
|
||||
securityGroup.Name,
|
||||
},
|
||||
Ami: pulumi.String(ami.Id),
|
||||
UserData: pulumi.String(fmt.Sprintf("%v%v%v", "#!/bin/bash\n", "echo \"Hello, World!\" > index.html\n", "nohup python -m SimpleHTTPServer 80 &\n")),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctx.Export("publicIp", server.PublicIp)
|
||||
ctx.Export("publicHostName", server.PublicDns)
|
||||
return nil
|
||||
})
|
||||
}
|
Loading…
Reference in a new issue