Skip to content

Commit

Permalink
Merge #11592 #11593
Browse files Browse the repository at this point in the history
11592: Don't use `*schema.Package` in .NET codegen r=iwahbe a=iwahbe

Part of #9932
Builds on #11578

tldr: Package is not reliable when its used for an external package. We are transferring over to PackageReference, and will remove the Package field once all references to it have been removed.

11593: Interpret schema.Asset as pcl.AssetOrArchive r=iwahbe a=iwahbe

Fixes #11572

Co-authored-by: Ian Wahbe <ian@wahbe.com>
  • Loading branch information
bors[bot] and iwahbe committed Dec 8, 2022
3 parents f6d669c + 6ff61ae + 8e99749 commit 43cfc49
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 51 deletions.
@@ -0,0 +1,4 @@
changes:
- type: fix
scope: programgen
description: Interpret schema.Asset as pcl.AssetOrArchive.
4 changes: 2 additions & 2 deletions pkg/codegen/dotnet/doc.go
Expand Up @@ -79,7 +79,7 @@ func (d DocLanguageHelper) GetLanguageTypeString(pkg *schema.Package, moduleName
}
typeDetails := map[*schema.ObjectType]*typeDetails{}
mod := &modContext{
pkg: pkg,
pkg: pkg.Reference(),
mod: moduleName,
typeDetails: typeDetails,
namespaces: d.Namespaces,
Expand Down Expand Up @@ -114,7 +114,7 @@ func (d DocLanguageHelper) GetMethodResultName(pkg *schema.Package, modName stri
if info.LiftSingleValueMethodReturns && m.Function.Outputs != nil && len(m.Function.Outputs.Properties) == 1 {
typeDetails := map[*schema.ObjectType]*typeDetails{}
mod := &modContext{
pkg: pkg,
pkg: pkg.Reference(),
mod: modName,
typeDetails: typeDetails,
namespaces: d.Namespaces,
Expand Down
105 changes: 61 additions & 44 deletions pkg/codegen/dotnet/gen.go
Expand Up @@ -125,7 +125,7 @@ func namespaceName(namespaces map[string]string, name string) string {
}

type modContext struct {
pkg *schema.Package
pkg schema.PackageReference
mod string
propertyNames map[*schema.Property]string
types []*schema.ObjectType
Expand Down Expand Up @@ -372,13 +372,15 @@ func (mod *modContext) typeString(t schema.Type, qualifier string, input, state,
return fmt.Sprintf("%v<string, %v>", mapType, mod.typeString(t.ElementType, qualifier, input, state, false))
case *schema.ObjectType:
namingCtx := mod
if t.Package != mod.pkg {
if !codegen.PkgEquals(t.PackageReference, mod.pkg) {
// If object type belongs to another package, we apply naming conventions from that package,
// including namespace naming and compatibility mode.
extPkg := t.Package
extPkg := t.PackageReference
var info CSharpPackageInfo
contract.AssertNoError(extPkg.ImportLanguages(map[string]schema.Language{"csharp": Importer}))
if v, ok := t.Package.Language["csharp"].(CSharpPackageInfo); ok {
def, err := extPkg.Definition()
contract.AssertNoError(err)
contract.AssertNoError(def.ImportLanguages(map[string]schema.Language{"csharp": Importer}))
if v, ok := def.Language["csharp"].(CSharpPackageInfo); ok {
info = v
}
namingCtx = &modContext{
Expand Down Expand Up @@ -406,13 +408,15 @@ func (mod *modContext) typeString(t schema.Type, qualifier string, input, state,
}

namingCtx := mod
if t.Resource != nil && t.Resource.Package != mod.pkg {
if t.Resource != nil && !codegen.PkgEquals(t.Resource.PackageReference, mod.pkg) {
// If resource type belongs to another package, we apply naming conventions from that package,
// including namespace naming and compatibility mode.
extPkg := t.Resource.Package
extPkg := t.Resource.PackageReference
var info CSharpPackageInfo
contract.AssertNoError(extPkg.ImportLanguages(map[string]schema.Language{"csharp": Importer}))
if v, ok := t.Resource.Package.Language["csharp"].(CSharpPackageInfo); ok {
def, err := extPkg.Definition()
contract.AssertNoError(err)
contract.AssertNoError(def.ImportLanguages(map[string]schema.Language{"csharp": Importer}))
if v, ok := def.Language["csharp"].(CSharpPackageInfo); ok {
info = v
}
namingCtx = &modContext{
Expand Down Expand Up @@ -906,7 +910,7 @@ func (mod *modContext) genResource(w io.Writer, r *schema.Resource) error {
if r.DeprecationMessage != "" {
fmt.Fprintf(w, " [Obsolete(@\"%s\")]\n", strings.Replace(r.DeprecationMessage, `"`, `""`, -1))
}
fmt.Fprintf(w, " [%sResourceType(\"%s\")]\n", namespaceName(mod.namespaces, mod.pkg.Name), r.Token)
fmt.Fprintf(w, " [%sResourceType(\"%s\")]\n", namespaceName(mod.namespaces, mod.pkg.Name()), r.Token)
fmt.Fprintf(w, " public partial class %s : %s\n", className, baseType)
fmt.Fprintf(w, " {\n")

Expand Down Expand Up @@ -967,7 +971,7 @@ func (mod *modContext) genResource(w io.Writer, r *schema.Resource) error {

tok := r.Token
if r.IsProvider {
tok = mod.pkg.Name
tok = mod.pkg.Name()
}

argsOverride := fmt.Sprintf("args ?? new %sArgs()", className)
Expand Down Expand Up @@ -1046,7 +1050,11 @@ func (mod *modContext) genResource(w io.Writer, r *schema.Resource) error {
fmt.Fprintf(w, " var defaultOptions = new %s\n", optionsType)
fmt.Fprintf(w, " {\n")
fmt.Fprintf(w, " Version = Utilities.Version,\n")
if url := mod.pkg.PluginDownloadURL; url != "" {
def, err := mod.pkg.Definition()
if err != nil {
return err
}
if url := def.PluginDownloadURL; url != "" {
fmt.Fprintf(w, " PluginDownloadURL = %q,\n", url)
}

Expand Down Expand Up @@ -1702,7 +1710,7 @@ func (mod *modContext) getTypeImportsForResource(t schema.Type, recurse bool, im
case *schema.ResourceType:
// If it's an external resource, we'll be using fully-qualified type names, so there's no need
// for an import.
if t.Resource != nil && t.Resource.Package != mod.pkg {
if t.Resource != nil && !codegen.PkgEquals(t.Resource.PackageReference, mod.pkg) {
return
}

Expand Down Expand Up @@ -1875,7 +1883,7 @@ func (mod *modContext) genConfig(variables []*schema.Property) (string, error) {
fmt.Fprintf(w, "\n")

// Create a config bag for the variables to pull from.
fmt.Fprintf(w, " private static readonly global::Pulumi.Config __config = new global::Pulumi.Config(\"%v\");\n", mod.pkg.Name)
fmt.Fprintf(w, " private static readonly global::Pulumi.Config __config = new global::Pulumi.Config(\"%v\");\n", mod.pkg.Name())
fmt.Fprintf(w, "\n")

// Emit an entry for all config variables.
Expand Down Expand Up @@ -1953,12 +1961,16 @@ func (mod *modContext) genConfig(variables []*schema.Property) (string, error) {
func (mod *modContext) genUtilities() (string, error) {
// Strip any 'v' off of the version.
w := &bytes.Buffer{}
err := csharpUtilitiesTemplate.Execute(w, csharpUtilitiesTemplateContext{
Name: namespaceName(mod.namespaces, mod.pkg.Name),
def, err := mod.pkg.Definition()
if err != nil {
return "", err
}
err = csharpUtilitiesTemplate.Execute(w, csharpUtilitiesTemplateContext{
Name: namespaceName(mod.namespaces, mod.pkg.Name()),
Namespace: mod.namespaceName,
ClassName: "Utilities",
Tool: mod.tool,
PluginDownloadURL: mod.pkg.PluginDownloadURL,
PluginDownloadURL: def.PluginDownloadURL,
})
if err != nil {
return "", err
Expand Down Expand Up @@ -1997,7 +2009,7 @@ func (mod *modContext) gen(fs codegen.Fs) error {
}

// Ensure that the target module directory contains a README.md file.
readme := mod.pkg.Description
readme := mod.pkg.Description()
if readme != "" && readme[len(readme)-1] != '\n' {
readme += "\n"
}
Expand All @@ -2012,8 +2024,12 @@ func (mod *modContext) gen(fs codegen.Fs) error {
}
fs.Add("Utilities.cs", []byte(utilities))
case "config":
if len(mod.pkg.Config) > 0 {
config, err := mod.genConfig(mod.pkg.Config)
config, err := mod.pkg.Config()
if err != nil {
return err
}
if len(config) > 0 {
config, err := mod.genConfig(config)
if err != nil {
return err
}
Expand Down Expand Up @@ -2252,19 +2268,20 @@ type LanguageResource struct {
func generateModuleContextMap(tool string, pkg *schema.Package) (map[string]*modContext, *CSharpPackageInfo, error) {
// Decode .NET-specific info for each package as we discover them.
infos := map[*schema.Package]*CSharpPackageInfo{}
var getPackageInfo = func(p *schema.Package) *CSharpPackageInfo {
info, ok := infos[p]
var getPackageInfo = func(p schema.PackageReference) *CSharpPackageInfo {
def, err := p.Definition()
contract.AssertNoError(err)
info, ok := infos[def]
if !ok {
if err := p.ImportLanguages(map[string]schema.Language{"csharp": Importer}); err != nil {
panic(err)
}
err := def.ImportLanguages(map[string]schema.Language{"csharp": Importer})
contract.AssertNoError(err)
csharpInfo, _ := pkg.Language["csharp"].(CSharpPackageInfo)
info = &csharpInfo
infos[p] = info
infos[def] = info
}
return info
}
infos[pkg] = getPackageInfo(pkg)
infos[pkg] = getPackageInfo(pkg.Reference())

propertyNames := map[*schema.Property]string{}
computePropertyNames(pkg.Config, propertyNames)
Expand Down Expand Up @@ -2304,8 +2321,8 @@ func generateModuleContextMap(tool string, pkg *schema.Package) (map[string]*mod
modules := map[string]*modContext{}
details := map[*schema.ObjectType]*typeDetails{}

var getMod func(modName string, p *schema.Package) *modContext
getMod = func(modName string, p *schema.Package) *modContext {
var getMod func(modName string, p schema.PackageReference) *modContext
getMod = func(modName string, p schema.PackageReference) *modContext {
mod, ok := modules[modName]
if !ok {
info := getPackageInfo(p)
Expand Down Expand Up @@ -2338,41 +2355,41 @@ func generateModuleContextMap(tool string, pkg *schema.Package) (map[string]*mod

// Save the module only if it's for the current package.
// This way, modules for external packages are not saved.
if p == pkg {
if codegen.PkgEquals(p, pkg.Reference()) {
modules[modName] = mod
}
}
return mod
}

getModFromToken := func(token string, p *schema.Package) *modContext {
getModFromToken := func(token string, p schema.PackageReference) *modContext {
return getMod(p.TokenToModule(token), p)
}

// Create the config module if necessary.
if len(pkg.Config) > 0 {
cfg := getMod("config", pkg)
cfg := getMod("config", pkg.Reference())
cfg.namespaceName = fmt.Sprintf("%s.%s", cfg.RootNamespace(), namespaceName(infos[pkg].Namespaces, pkg.Name))
}

visitObjectTypes(pkg.Config, func(t *schema.ObjectType) {
getModFromToken(t.Token, pkg).details(t).outputType = true
getModFromToken(t.Token, pkg.Reference()).details(t).outputType = true
})

// Find input and output types referenced by resources.
scanResource := func(r *schema.Resource) {
mod := getModFromToken(r.Token, pkg)
mod := getModFromToken(r.Token, pkg.Reference())
mod.resources = append(mod.resources, r)
visitObjectTypes(r.Properties, func(t *schema.ObjectType) {
getModFromToken(t.Token, t.Package).details(t).outputType = true
getModFromToken(t.Token, t.PackageReference).details(t).outputType = true
})
visitObjectTypes(r.InputProperties, func(t *schema.ObjectType) {
getModFromToken(t.Token, t.Package).details(t).inputType = true
getModFromToken(t.Token, t.PackageReference).details(t).inputType = true
})
if r.StateInputs != nil {
visitObjectTypes(r.StateInputs.Properties, func(t *schema.ObjectType) {
getModFromToken(t.Token, t.Package).details(t).inputType = true
getModFromToken(t.Token, t.Package).details(t).stateType = true
getModFromToken(t.Token, t.PackageReference).details(t).inputType = true
getModFromToken(t.Token, t.PackageReference).details(t).stateType = true
})
}
}
Expand All @@ -2389,27 +2406,27 @@ func generateModuleContextMap(tool string, pkg *schema.Package) (map[string]*mod
continue
}

mod := getModFromToken(f.Token, pkg)
mod := getModFromToken(f.Token, pkg.Reference())
if !f.IsMethod {
mod.functions = append(mod.functions, f)
}
if f.Inputs != nil {
visitObjectTypes(f.Inputs.Properties, func(t *schema.ObjectType) {
details := getModFromToken(t.Token, t.Package).details(t)
details := getModFromToken(t.Token, t.PackageReference).details(t)
details.inputType = true
details.plainType = true
})
if f.NeedsOutputVersion() {
visitObjectTypes(f.Inputs.InputShape.Properties, func(t *schema.ObjectType) {
details := getModFromToken(t.Token, t.Package).details(t)
details := getModFromToken(t.Token, t.PackageReference).details(t)
details.inputType = true
details.usedInFunctionOutputVersionInputs = true
})
}
}
if f.Outputs != nil {
visitObjectTypes(f.Outputs.Properties, func(t *schema.ObjectType) {
details := getModFromToken(t.Token, t.Package).details(t)
details := getModFromToken(t.Token, t.PackageReference).details(t)
details.outputType = true
details.plainType = true
})
Expand All @@ -2420,11 +2437,11 @@ func generateModuleContextMap(tool string, pkg *schema.Package) (map[string]*mod
for _, t := range pkg.Types {
switch typ := t.(type) {
case *schema.ObjectType:
mod := getModFromToken(typ.Token, pkg)
mod := getModFromToken(typ.Token, pkg.Reference())
mod.types = append(mod.types, typ)
case *schema.EnumType:
if !typ.IsOverlay {
mod := getModFromToken(typ.Token, pkg)
mod := getModFromToken(typ.Token, pkg.Reference())
mod.enums = append(mod.enums, typ)
}
default:
Expand Down
6 changes: 4 additions & 2 deletions pkg/codegen/dotnet/gen_program.go
Expand Up @@ -316,8 +316,10 @@ func (g *generator) genPreamble(w io.Writer, program *pcl.Program) {
if pkg != pulumiPackage {
namespace := namespaceName(g.namespaces[pkg], pkg)
var info CSharpPackageInfo
if r.Schema != nil && r.Schema.Package != nil {
if csharpinfo, ok := r.Schema.Package.Language["csharp"].(CSharpPackageInfo); ok {
if r.Schema != nil && r.Schema.PackageReference != nil {
def, err := r.Schema.PackageReference.Definition()
contract.AssertNoError(err)
if csharpinfo, ok := def.Language["csharp"].(CSharpPackageInfo); ok {
info = csharpinfo
}
}
Expand Down
4 changes: 3 additions & 1 deletion pkg/codegen/dotnet/gen_program_expressions.go
Expand Up @@ -301,7 +301,9 @@ func enumName(enum *model.EnumType) (string, string) {
if !ok {
return "", ""
}
namespaceMap := e.(*schema.EnumType).Package.Language["csharp"].(CSharpPackageInfo).Namespaces
def, err := e.(*schema.EnumType).PackageReference.Definition()
contract.AssertNoError(err)
namespaceMap := def.Language["csharp"].(CSharpPackageInfo).Namespaces
namespace := namespaceName(namespaceMap, components[0])
if components[1] != "" && components[1] != "index" {
namespace += "." + namespaceName(namespaceMap, components[1])
Expand Down
6 changes: 5 additions & 1 deletion pkg/codegen/pcl/binder_schema.go
Expand Up @@ -389,7 +389,11 @@ func (b *binder) schemaTypeToType(src schema.Type) model.Type {
case schema.ArchiveType:
return ArchiveType
case schema.AssetType:
return AssetType
// Generated SDK code accepts assets or archives when schema.AssetType is
// specified. In an effort to keep PCL type checking in sync with our
// generated SDKs, we match the SDKs behavior when translating schema types to
// PCL types.
return AssetOrArchiveType
case schema.JSONType:
fallthrough
case schema.AnyType:
Expand Down
1 change: 0 additions & 1 deletion pkg/codegen/testing/test/program_driver.go
Expand Up @@ -249,7 +249,6 @@ var PulumiPulumiYAMLProgramTests = []ProgramTest{
Directory: transpiled("azure-app-service"),
Description: "Azure App Service",
Skip: codegen.NewStringSet("go", "dotnet"),
BindOptions: []pcl.BindOption{pcl.SkipResourceTypechecking},
},
{
Directory: transpiled("azure-container-apps"),
Expand Down

0 comments on commit 43cfc49

Please sign in to comment.