Skip to content

Commit

Permalink
Refine path model and path assumptions (#661)
Browse files Browse the repository at this point in the history
  • Loading branch information
t0yv0 committed Dec 6, 2022
1 parent cdc390c commit 1ad22a8
Show file tree
Hide file tree
Showing 4 changed files with 354 additions and 229 deletions.
10 changes: 5 additions & 5 deletions pkg/tfgen/docs.go
Expand Up @@ -1624,10 +1624,10 @@ func fixupPropertyReferences(language Language, pkg tokens.Package, info tfbridg
switch language {
case Golang, Python:
// Use `ec2.Instance` format
return open + modname + resname + close
return open + modname + resname.String() + close
default:
// Use `aws.ec2.Instance` format
return open + pkg.String() + "." + modname + resname + close
return open + pkg.String() + "." + modname + resname.String() + close
}
} else if dataInfo, hasDatasourceInfo := info.DataSources[name]; hasDatasourceInfo {
// This is a data source name
Expand All @@ -1636,13 +1636,13 @@ func fixupPropertyReferences(language Language, pkg tokens.Package, info tfbridg
switch language {
case Golang:
// Use `ec2.getAmi` format
return open + modname + getname + close
return open + modname + getname.String() + close
case Python:
// Use `ec2.get_ami` format
return python.PyName(open + modname + getname + close)
return python.PyName(open + modname + getname.String() + close)
default:
// Use `aws.ec2.getAmi` format
return open + pkg.String() + "." + modname + getname + close
return open + pkg.String() + "." + modname + getname.String() + close
}
}
// Else just treat as a property name
Expand Down
159 changes: 100 additions & 59 deletions pkg/tfgen/generate.go
Expand Up @@ -43,6 +43,7 @@ import (

"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tf2pulumi/il"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfgen/internal/paths"
shim "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim/schema"
schemaTools "github.com/pulumi/schema-tools/pkg"
Expand Down Expand Up @@ -300,7 +301,8 @@ type propertyType struct {
asset *tfbridge.AssetTranslation
}

func makePropertyType(objectName string, sch shim.Schema, info *tfbridge.SchemaInfo, out bool,
func (g *Generator) makePropertyType(typePath paths.TypePath,
objectName string, sch shim.Schema, info *tfbridge.SchemaInfo, out bool,
entityDocs entityDocs) *propertyType {

t := &propertyType{}
Expand Down Expand Up @@ -343,9 +345,11 @@ func makePropertyType(objectName string, sch shim.Schema, info *tfbridge.SchemaI

switch elem := sch.Elem().(type) {
case shim.Schema:
t.element = makePropertyType(objectName, elem, elemInfo, out, entityDocs)
t.element = g.makePropertyType(paths.NewElementPath(typePath),
objectName, elem, elemInfo, out, entityDocs)
case shim.Resource:
t.element = makeObjectPropertyType(objectName, elem, elemInfo, out, entityDocs)
t.element = g.makeObjectPropertyType(paths.NewElementPath(typePath),
objectName, elem, elemInfo, out, entityDocs)
}

switch t.kind {
Expand All @@ -364,8 +368,9 @@ func makePropertyType(objectName string, sch shim.Schema, info *tfbridge.SchemaI
return t
}

func makeObjectPropertyType(objectName string, res shim.Resource, info *tfbridge.SchemaInfo, out bool,
entityDocs entityDocs) *propertyType {
func (g *Generator) makeObjectPropertyType(typePath paths.TypePath,
objectName string, res shim.Resource, info *tfbridge.SchemaInfo,
out bool, entityDocs entityDocs) *propertyType {

t := &propertyType{
kind: kindObject,
Expand Down Expand Up @@ -396,7 +401,8 @@ func makeObjectPropertyType(objectName string, res shim.Resource, info *tfbridge
// This seems wrong, so we ignore the second return value here for now.
doc, _ := getNestedDescriptionFromParsedDocs(entityDocs, objectName, key)

if v := propertyVariable(key, propertySchema, propertyInfo, doc, "", out, entityDocs); v != nil {
if v := g.propertyVariable(typePath, key,
propertySchema, propertyInfo, doc, "", out, entityDocs); v != nil {
t.properties = append(t.properties, v)
}
}
Expand Down Expand Up @@ -472,6 +478,9 @@ type variable struct {
info *tfbridge.SchemaInfo

typ *propertyType

parentPath paths.TypePath
propertyName paths.PropertyName
}

func (v *variable) Name() string { return v.name }
Expand Down Expand Up @@ -539,6 +548,8 @@ type resourceType struct {
schema shim.Resource
info *tfbridge.ResourceInfo
entityDocs entityDocs // parsed docs.

resourcePath *paths.ResourcePath
}

func (rt *resourceType) Name() string { return rt.name }
Expand All @@ -551,7 +562,8 @@ func (rt *resourceType) TypeToken() tokens.Type {
return tokens.NewTypeToken(rt.mod, tokens.TypeName(rt.name))
}

func newResourceType(mod tokens.Module, name string, entityDocs entityDocs,
func newResourceType(resourcePath *paths.ResourcePath,
mod tokens.Module, name tokens.TypeName, entityDocs entityDocs,
schema shim.Resource, info *tfbridge.ResourceInfo,
isProvider bool) *resourceType {

Expand All @@ -562,30 +574,32 @@ func newResourceType(mod tokens.Module, name string, entityDocs entityDocs,
}

return &resourceType{
mod: mod,
name: name,
doc: description,
isProvider: isProvider,
schema: schema,
info: info,
reqprops: make(map[string]bool),
entityDocs: entityDocs,
mod: mod,
name: name.String(),
doc: description,
isProvider: isProvider,
schema: schema,
info: info,
reqprops: make(map[string]bool),
entityDocs: entityDocs,
resourcePath: resourcePath,
}
}

// resourceFunc is a generated resource function that is exposed to interact with Pulumi objects.
type resourceFunc struct {
mod tokens.Module
name string
doc string
args []*variable
rets []*variable
reqargs map[string]bool
argst *propertyType
retst *propertyType
schema shim.Resource
info *tfbridge.DataSourceInfo
entityDocs entityDocs
mod tokens.Module
name string
doc string
args []*variable
rets []*variable
reqargs map[string]bool
argst *propertyType
retst *propertyType
schema shim.Resource
info *tfbridge.DataSourceInfo
entityDocs entityDocs
dataSourcePath *paths.DataSourcePath
}

func (rf *resourceFunc) Name() string { return rf.name }
Expand Down Expand Up @@ -907,11 +921,14 @@ func (g *Generator) gatherConfig() *module {
})
sort.Strings(cfgkeys)

cfgPath := paths.NewConfigPath()

// Add an entry for each config variable.
for _, key := range cfgkeys {
// Generate a name and type to use for this key.
sch := cfg.Get(key)
prop := propertyVariable(key, sch, custom[key], "", sch.Description(), true /*out*/, entityDocs{})
prop := g.propertyVariable(cfgPath,
key, sch, custom[key], "", sch.Description(), true /*out*/, entityDocs{})
if prop != nil {
prop.config = true
config.addMember(prop)
Expand All @@ -927,7 +944,8 @@ func (g *Generator) gatherConfig() *module {

// Now, if there are any extra config variables, that are Pulumi-only, add them.
for key, val := range g.info.ExtraConfig {
if prop := propertyVariable(key, val.Schema, val.Info, "", "", true /*out*/, entityDocs{}); prop != nil {
if prop := g.propertyVariable(cfgPath,
key, val.Schema, val.Info, "", "", true /*out*/, entityDocs{}); prop != nil {
prop.config = true
config.addMember(prop)
}
Expand Down Expand Up @@ -1036,6 +1054,9 @@ func (g *Generator) gatherResource(rawname string,
name, moduleName := resourceName(g.info.Name, rawname, info, isProvider)
mod := tokens.NewModuleToken(g.pkg, moduleName)

resourceToken := tokens.NewTypeToken(mod, name)
resourcePath := paths.NewResourcePath(rawname, resourceToken, isProvider)

// Collect documentation information
var entityDocs entityDocs
if !isProvider {
Expand All @@ -1056,7 +1077,7 @@ func (g *Generator) gatherResource(rawname string,
}

// Create an empty module and associated resource type.
res := newResourceType(mod, name, entityDocs, schema, info, isProvider)
res := newResourceType(resourcePath, mod, name, entityDocs, schema, info, isProvider)

// Next, gather up all properties.
var stateVars []*variable
Expand All @@ -1077,7 +1098,8 @@ func (g *Generator) gatherResource(rawname string,
if !isProvider {
// For all properties, generate the output property metadata. Note that this may differ slightly
// from the input in that the types may differ.
outprop := propertyVariable(key, propschema, propinfo, doc, rawdoc, true /*out*/, entityDocs)
outprop := g.propertyVariable(resourcePath.Outputs(), key, propschema,
propinfo, doc, rawdoc, true /*out*/, entityDocs)
if outprop != nil {
res.outprops = append(res.outprops, outprop)
}
Expand All @@ -1091,17 +1113,19 @@ func (g *Generator) gatherResource(rawname string,
g.debug(msg)
}

inprop := propertyVariable(key, propschema, propinfo, doc, rawdoc, false /*out*/, entityDocs)
inprop := g.propertyVariable(resourcePath.Inputs(),
key, propschema, propinfo, doc, rawdoc, false /*out*/, entityDocs)
if inprop != nil {
res.inprops = append(res.inprops, inprop)
if !inprop.optional() {
res.reqprops[name] = true
res.reqprops[name.String()] = true
}
}
}

// Make a state variable. This is always optional and simply lets callers perform lookups.
stateVar := propertyVariable(key, propschema, propinfo, doc, rawdoc, false /*out*/, entityDocs)
stateVar := g.propertyVariable(resourcePath.State(), key, propschema, propinfo,
doc, rawdoc, false /*out*/, entityDocs)
stateVar.opt = true
stateVars = append(stateVars, stateVar)
}
Expand Down Expand Up @@ -1226,6 +1250,7 @@ func (g *Generator) gatherDataSource(rawname string,
// Generate the name and module for this data source.
name, moduleName := dataSourceName(g.info.Name, rawname, info)
mod := tokens.NewModuleToken(g.pkg, moduleName)
dataSourcePath := paths.NewDataSourcePath(rawname, tokens.NewModuleMemberToken(mod, name))

// Collect documentation information for this data source.
entityDocs, err := getDocsForProvider(g, g.info.GetGitHubOrg(), g.info.Name,
Expand All @@ -1237,13 +1262,14 @@ func (g *Generator) gatherDataSource(rawname string,

// Build up the function information.
fun := &resourceFunc{
mod: mod,
name: name,
doc: entityDocs.Description,
reqargs: make(map[string]bool),
schema: ds,
info: info,
entityDocs: entityDocs,
mod: mod,
name: name.String(),
doc: entityDocs.Description,
reqargs: make(map[string]bool),
schema: ds,
info: info,
entityDocs: entityDocs,
dataSourcePath: dataSourcePath,
}

// See if arguments for this function are optional, and generate detailed metadata.
Expand All @@ -1264,7 +1290,8 @@ func (g *Generator) gatherDataSource(rawname string,
g.debug(msg)
}

argvar := propertyVariable(arg, sch, cust, doc, "", false /*out*/, entityDocs)
argvar := g.propertyVariable(dataSourcePath.Args(),
arg, sch, cust, doc, "", false /*out*/, entityDocs)
fun.args = append(fun.args, argvar)
if !argvar.optional() {
fun.reqargs[argvar.name] = true
Expand All @@ -1274,7 +1301,8 @@ func (g *Generator) gatherDataSource(rawname string,
// Also remember properties for the resulting return data structure.
// Emit documentation for the property if available
fun.rets = append(fun.rets,
propertyVariable(arg, sch, cust, entityDocs.Attributes[arg], "", true /*out*/, entityDocs))
g.propertyVariable(dataSourcePath.Results(),
arg, sch, cust, entityDocs.Attributes[arg], "", true /*out*/, entityDocs))
}

// If the data source's schema doesn't expose an id property, make one up since we'd like to expose it for data
Expand All @@ -1284,22 +1312,23 @@ func (g *Generator) gatherDataSource(rawname string,
rawdoc := "The provider-assigned unique ID for this managed resource."
idSchema := &schema.Schema{Type: shim.TypeString, Computed: true}
fun.rets = append(fun.rets,
propertyVariable("id", idSchema.Shim(), cust, "", rawdoc, true /*out*/, entityDocs))
g.propertyVariable(dataSourcePath.Results(),
"id", idSchema.Shim(), cust, "", rawdoc, true /*out*/, entityDocs))
}

// Produce the args/return types, if needed.
if len(fun.args) > 0 {
fun.argst = &propertyType{
kind: kindObject,
name: fmt.Sprintf("%sArgs", upperFirst(name)),
name: fmt.Sprintf("%sArgs", upperFirst(name.String())),
doc: fmt.Sprintf("A collection of arguments for invoking %s.", name),
properties: fun.args,
}
}
if len(fun.rets) > 0 {
fun.retst = &propertyType{
kind: kindObject,
name: fmt.Sprintf("%sResult", upperFirst(name)),
name: fmt.Sprintf("%sResult", upperFirst(name.String())),
doc: fmt.Sprintf("A collection of values returned by %s.", name),
properties: fun.rets,
}
Expand Down Expand Up @@ -1401,37 +1430,49 @@ func propertyName(key string, sch shim.Schema, custom *tfbridge.SchemaInfo) stri
}

// propertyVariable creates a new property, with the Pulumi name, out of the given components.
func propertyVariable(key string, sch shim.Schema, info *tfbridge.SchemaInfo,
//
// key is the Terraform property name
//
// parentPath together with key uniquely locates the property in the Terraform schema.
func (g *Generator) propertyVariable(parentPath paths.TypePath, key string,
sch shim.Schema, info *tfbridge.SchemaInfo,
doc string, rawdoc string, out bool, entityDocs entityDocs) *variable {

if name := propertyName(key, sch, info); name != "" {
propName := paths.PropertyName{Key: key, Name: tokens.Name(name)}
typePath := paths.NewProperyPath(parentPath, propName)

return &variable{
name: name,
out: out,
doc: doc,
rawdoc: rawdoc,
schema: sch,
info: info,
typ: makePropertyType(strings.ToLower(key), sch, info, out, entityDocs),
name: name,
out: out,
doc: doc,
rawdoc: rawdoc,
schema: sch,
info: info,
typ: g.makePropertyType(typePath, strings.ToLower(key), sch, info, out, entityDocs),
parentPath: parentPath,
propertyName: propName,
}
}
return nil
}

// dataSourceName translates a Terraform name into its Pulumi name equivalent.
func dataSourceName(provider string, rawname string, info *tfbridge.DataSourceInfo) (string, tokens.ModuleName) {
func dataSourceName(provider string, rawname string,
info *tfbridge.DataSourceInfo) (tokens.ModuleMemberName, tokens.ModuleName) {
if info == nil || info.Tok == "" {
// default transformations.
name := withoutPackageName(provider, rawname) // strip off the pkg prefix.
name = tfbridge.TerraformToPulumiName(name, nil, nil, false) // camelCase
return name, tokens.ModuleName(name)
return tokens.ModuleMemberName(name), tokens.ModuleName(name)
}
// otherwise, a custom transformation exists; use it.
return string(info.Tok.Name()), info.Tok.Module().Name()
return info.Tok.Name(), info.Tok.Module().Name()
}

// resourceName translates a Terraform name into its Pulumi name equivalent, plus a module name.
func resourceName(provider string, rawname string,
info *tfbridge.ResourceInfo, isProvider bool) (string, tokens.ModuleName) {
info *tfbridge.ResourceInfo, isProvider bool) (tokens.TypeName, tokens.ModuleName) {
if isProvider {
return "Provider", indexMod
}
Expand All @@ -1442,10 +1483,10 @@ func resourceName(provider string, rawname string,
pascal := tfbridge.TerraformToPulumiName(name, nil, nil, true) // PascalCase the resource name.

modName := tokens.ModuleName(camel)
return pascal, modName
return tokens.TypeName(pascal), modName
}
// otherwise, a custom transformation exists; use it.
return info.Tok.Name().String(), info.Tok.Module().Name()
return info.Tok.Name(), info.Tok.Module().Name()
}

// withoutPackageName strips off the package prefix from a raw name.
Expand Down

0 comments on commit 1ad22a8

Please sign in to comment.