Programgen support for F.Invoke forms in .NET (#7949) (#8432)

* Implement .NET codegen for F.Invoke forms

* Add tests for .NET Invoke

* Fixed conflict

* Accept changes reverting fargate example
This commit is contained in:
Anton Tayanovskyy 2021-11-18 17:53:17 -05:00 committed by GitHub
parent e846b3201f
commit e60d6bf248
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 132 additions and 11 deletions

View file

@ -8,6 +8,10 @@
appropriate, simplifying auto-generated examples.
[#8431](https://github.com/pulumi/pulumi/pull/8431)
- [codegen/dotnet] - Program generator now uses `Invoke` forms where
appropriate, simplifying auto-generated examples.
[#8432](https://github.com/pulumi/pulumi/pull/8432)
### Bug Fixes
- [codegen/typescript] - Respect default values in Pulumi object types.

View file

@ -1,4 +1,4 @@
// Copyright 2016-2020, Pulumi Corporation.
// Copyright 2016-2021, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -46,6 +46,9 @@ type generator struct {
asyncInit bool
configCreated bool
diagnostics hcl.Diagnostics
// Helper map to emit custom type name suffixes that match
// those emitted by codegen.
usedInFunctionOutputVersionInputs map[schema.Type]bool
}
const pulumiPackage = "pulumi"
@ -343,14 +346,32 @@ func (g *generator) functionName(tokenArg model.Expression) (string, string) {
return rootNamespace, fmt.Sprintf("%s%s.%s", rootNamespace, namespace, Title(member))
}
func (g *generator) toSchemaType(destType model.Type) (schema.Type, bool) {
schemaType, ok := pcl.GetSchemaForType(destType.(model.Type))
if !ok {
return nil, false
}
return codegen.UnwrapType(schemaType), true
}
// argumentTypeName computes the C# argument class name for the given expression and model type.
func (g *generator) argumentTypeName(expr model.Expression, destType model.Type) string {
schemaType, ok := pcl.GetSchemaForType(destType.(model.Type))
schemaType, ok := g.toSchemaType(destType)
if !ok {
return ""
}
suffix := "Args"
if g.usedInFunctionOutputVersionInputs[schemaType] {
suffix = "InputArgs"
}
return g.argumentTypeNameWithSuffix(expr, destType, suffix)
}
schemaType = codegen.UnwrapType(schemaType)
func (g *generator) argumentTypeNameWithSuffix(expr model.Expression, destType model.Type, suffix string) string {
schemaType, ok := g.toSchemaType(destType)
if !ok {
return ""
}
objType, ok := schemaType.(*schema.ObjectType)
if !ok {
@ -382,7 +403,7 @@ func (g *generator) argumentTypeName(expr model.Expression, destType model.Type)
} else if qualifier != "" {
namespace = namespace + "." + qualifier
}
member = member + "Args"
member = member + suffix
return fmt.Sprintf("%s%s.%s", rootNamespace, namespace, Title(member))
}

View file

@ -255,6 +255,28 @@ func (g *generator) genFunctionUsings(x *model.FunctionCallExpression) []string
return []string{fmt.Sprintf("%s = Pulumi.%[1]s", pkg)}
}
func (g *generator) markTypeAsUsedInFunctionOutputVersionInputs(t model.Type) {
if g.usedInFunctionOutputVersionInputs == nil {
g.usedInFunctionOutputVersionInputs = make(map[schema.Type]bool)
}
schemaType, ok := g.toSchemaType(t)
if !ok {
return
}
g.usedInFunctionOutputVersionInputs[schemaType] = true
}
func (g *generator) visitToMarkTypesUsedInFunctionOutputVersionInputs(expr model.Expression) {
visitor := func(expr model.Expression) (model.Expression, hcl.Diagnostics) {
isCons, _, t := pcl.RecognizeTypedObjectCons(expr)
if isCons {
g.markTypeAsUsedInFunctionOutputVersionInputs(t)
}
return expr, nil
}
model.VisitExpression(expr, nil, visitor) // nolint:errcheck
}
func (g *generator) GenFunctionCallExpression(w io.Writer, expr *model.FunctionCallExpression) {
switch expr.Name {
case pcl.IntrinsicConvert:
@ -294,10 +316,19 @@ func (g *generator) GenFunctionCallExpression(w io.Writer, expr *model.FunctionC
case pcl.Invoke:
_, name := g.functionName(expr.Args[0])
g.Fprintf(w, "%s.InvokeAsync(", name)
if len(expr.Args) >= 2 {
g.Fgenf(w, "%.v", expr.Args[1])
isOut, outArgs, outArgsTy := pcl.RecognizeOutputVersionedInvoke(expr)
if isOut {
g.visitToMarkTypesUsedInFunctionOutputVersionInputs(outArgs)
g.Fprintf(w, "%s.Invoke(", name)
typeName := g.argumentTypeNameWithSuffix(expr, outArgsTy, "InvokeArgs")
g.genObjectConsExpressionWithTypeName(w, outArgs, typeName)
} else {
g.Fprintf(w, "%s.InvokeAsync(", name)
if len(expr.Args) >= 2 {
g.Fgenf(w, "%.v", expr.Args[1])
}
}
if len(expr.Args) == 3 {
g.Fgenf(w, ", %.v", expr.Args[2])
}
@ -446,7 +477,18 @@ func (g *generator) genObjectConsExpression(w io.Writer, expr *model.ObjectConsE
return
}
typeName := g.argumentTypeName(expr, destType)
destTypeName := g.argumentTypeName(expr, destType)
g.genObjectConsExpressionWithTypeName(w, expr, destTypeName)
}
func (g *generator) genObjectConsExpressionWithTypeName(
w io.Writer, expr *model.ObjectConsExpression, destTypeName string) {
if len(expr.Items) == 0 {
return
}
typeName := destTypeName
if typeName != "" {
g.Fgenf(w, "new %s", typeName)
g.Fgenf(w, "\n%s{\n", g.Indent)

View file

@ -52,8 +52,6 @@ var programTests = []programTest{
// TODO[pulumi/pulumi#8440]
SkipCompile: codegen.NewStringSet("go"),
Skip: codegen.NewStringSet("dotnet"),
},
{
Name: "aws-s3-logging",
@ -130,7 +128,6 @@ var programTests = []programTest{
{
Name: "output-funcs-aws",
Description: "Output Versioned Functions",
Skip: codegen.NewStringSet("dotnet"),
},
}

View file

@ -0,0 +1,57 @@
using Pulumi;
using Aws = Pulumi.Aws;
class MyStack : Stack
{
public MyStack()
{
var aws_vpc = new Aws.Ec2.Vpc("aws_vpc", new Aws.Ec2.VpcArgs
{
CidrBlock = "10.0.0.0/16",
InstanceTenancy = "default",
});
var privateS3VpcEndpoint = new Aws.Ec2.VpcEndpoint("privateS3VpcEndpoint", new Aws.Ec2.VpcEndpointArgs
{
VpcId = aws_vpc.Id,
ServiceName = "com.amazonaws.us-west-2.s3",
});
var privateS3PrefixList = Aws.Ec2.GetPrefixList.Invoke(new Aws.Ec2.GetPrefixListInvokeArgs
{
PrefixListId = privateS3VpcEndpoint.PrefixListId,
});
var bar = new Aws.Ec2.NetworkAcl("bar", new Aws.Ec2.NetworkAclArgs
{
VpcId = aws_vpc.Id,
});
var privateS3NetworkAclRule = new Aws.Ec2.NetworkAclRule("privateS3NetworkAclRule", new Aws.Ec2.NetworkAclRuleArgs
{
NetworkAclId = bar.Id,
RuleNumber = 200,
Egress = false,
Protocol = "tcp",
RuleAction = "allow",
CidrBlock = privateS3PrefixList.Apply(privateS3PrefixList => privateS3PrefixList.CidrBlocks[0]),
FromPort = 443,
ToPort = 443,
});
var amis = Aws.Ec2.GetAmiIds.Invoke(new Aws.Ec2.GetAmiIdsInvokeArgs
{
Owners =
{
bar.Id,
},
Filters =
{
new Aws.Ec2.Inputs.GetAmiIdsFilterInputArgs
{
Name = bar.Id,
Values =
{
"pulumi*",
},
},
},
});
}
}