Skip to content

Commit

Permalink
Warn about using the core Asset and Archive types
Browse files Browse the repository at this point in the history
  • Loading branch information
thomas11 committed Jun 11, 2024
1 parent 305fb58 commit fbd137e
Show file tree
Hide file tree
Showing 11 changed files with 72 additions and 51 deletions.
8 changes: 4 additions & 4 deletions infer/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,16 +59,16 @@ func Component[R ComponentResource[I, O], I any, O pulumi.ComponentResource]() I

type derivedComponentController[R ComponentResource[I, O], I any, O pulumi.ComponentResource] struct{}

func (rc *derivedComponentController[R, I, O]) GetSchema(reg schema.RegisterDerivativeType) (
func (rc *derivedComponentController[R, I, O]) GetSchema(ctx context.Context, reg schema.RegisterDerivativeType) (
pschema.ResourceSpec, error) {
r, err := getResourceSchema[R, I, O](true)
r, err := getResourceSchema[R, I, O](ctx, true)
if err := err.ErrorOrNil(); err != nil {
return pschema.ResourceSpec{}, err
}
if err := registerTypes[I](reg); err != nil {
if err := registerTypes[I](ctx, reg); err != nil {
return pschema.ResourceSpec{}, err
}
if err := registerTypes[O](reg); err != nil {
if err := registerTypes[O](ctx, reg); err != nil {
return pschema.ResourceSpec{}, err
}
return r, nil
Expand Down
10 changes: 5 additions & 5 deletions infer/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,11 @@ func (*config[T]) underlyingType() reflect.Type {
}

func (*config[T]) GetToken() (tokens.Type, error) { return "pulumi:providers:pkg", nil }
func (*config[T]) GetSchema(reg schema.RegisterDerivativeType) (pschema.ResourceSpec, error) {
if err := registerTypes[T](reg); err != nil {
func (*config[T]) GetSchema(ctx context.Context, reg schema.RegisterDerivativeType) (pschema.ResourceSpec, error) {
if err := registerTypes[T](ctx, reg); err != nil {
return pschema.ResourceSpec{}, err
}
r, errs := getResourceSchema[T, T, T](false)
r, errs := getResourceSchema[T, T, T](ctx, false)
return r, errs.ErrorOrNil()
}

Expand All @@ -85,7 +85,7 @@ func (c *config[T]) checkConfig(ctx context.Context, req p.CheckRequest) (p.Chec
t = reflect.New(v.Type().Elem()).Interface().(T)
}

r, err := c.GetSchema(func(tokens.Type, pschema.ComplexTypeSpec) bool { return false })
r, err := c.GetSchema(ctx, func(tokens.Type, pschema.ComplexTypeSpec) bool { return false })
if err != nil {
return p.CheckResponse{}, fmt.Errorf("could not get config secrets: %w", err)
}
Expand Down Expand Up @@ -181,7 +181,7 @@ func (c *config[T]) handleConfigFailures(ctx context.Context, err mapper.Mapping
}

pkgName := p.GetRunInfo(ctx).PackageName
schema, mErr := c.GetSchema(func(tokens.Type, pschema.ComplexTypeSpec) bool { return false })
schema, mErr := c.GetSchema(ctx, func(tokens.Type, pschema.ComplexTypeSpec) bool { return false })
if mErr != nil {
return mErr
}
Expand Down
16 changes: 9 additions & 7 deletions infer/function.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,23 +78,25 @@ func fnToken(tk tokens.Type) tokens.Type {
return tokens.NewTypeToken(tk.Module(), tokens.TypeName(name))
}

func (*derivedInvokeController[F, I, O]) GetSchema(reg schema.RegisterDerivativeType) (pschema.FunctionSpec, error) {
func (*derivedInvokeController[F, I, O]) GetSchema(
ctx context.Context, reg schema.RegisterDerivativeType,
) (pschema.FunctionSpec, error) {
var f F
descriptions := getAnnotated(reflect.TypeOf(f))

input, err := objectSchema(reflect.TypeOf(new(I)))
input, err := objectSchema(ctx, reflect.TypeOf(new(I)))
if err != nil {
return pschema.FunctionSpec{}, err
}
output, err := objectSchema(reflect.TypeOf(new(O)))
output, err := objectSchema(ctx, reflect.TypeOf(new(O)))
if err != nil {
return pschema.FunctionSpec{}, err
}

if err := registerTypes[I](reg); err != nil {
if err := registerTypes[I](ctx, reg); err != nil {
return pschema.FunctionSpec{}, err
}
if err := registerTypes[O](reg); err != nil {
if err := registerTypes[O](ctx, reg); err != nil {
return pschema.FunctionSpec{}, err
}

Expand All @@ -105,9 +107,9 @@ func (*derivedInvokeController[F, I, O]) GetSchema(reg schema.RegisterDerivative
}, nil
}

func objectSchema(t reflect.Type) (*pschema.ObjectTypeSpec, error) {
func objectSchema(ctx context.Context, t reflect.Type) (*pschema.ObjectTypeSpec, error) {
descriptions := getAnnotated(t)
props, required, err := propertyListFromType(t, false)
props, required, err := propertyListFromType(ctx, t, false)
if err != nil {
return nil, fmt.Errorf("could not serialize input type %s: %w", t, err)
}
Expand Down
10 changes: 5 additions & 5 deletions infer/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -806,15 +806,15 @@ type derivedResourceController[R CustomResource[I, O], I, O any] struct{}

func (*derivedResourceController[R, I, O]) isInferredResource() {}

func (*derivedResourceController[R, I, O]) GetSchema(reg schema.RegisterDerivativeType) (
func (*derivedResourceController[R, I, O]) GetSchema(ctx context.Context, reg schema.RegisterDerivativeType) (
pschema.ResourceSpec, error) {
if err := registerTypes[I](reg); err != nil {
if err := registerTypes[I](ctx, reg); err != nil {
return pschema.ResourceSpec{}, err
}
if err := registerTypes[O](reg); err != nil {
if err := registerTypes[O](ctx, reg); err != nil {
return pschema.ResourceSpec{}, err
}
r, errs := getResourceSchema[R, I, O](false)
r, errs := getResourceSchema[R, I, O](ctx, false)
return r, errs.ErrorOrNil()
}

Expand Down Expand Up @@ -940,7 +940,7 @@ func (rc *derivedResourceController[R, I, O]) Diff(ctx context.Context, req p.Di
_, hasUpdate := ((interface{})(*r)).(CustomUpdate[I, O])
var forceReplace func(string) bool
if hasUpdate {
schema, err := rc.GetSchema(func(tokens.Type, pschema.ComplexTypeSpec) bool { return false })
schema, err := rc.GetSchema(ctx, func(tokens.Type, pschema.ComplexTypeSpec) bool { return false })
if err != nil {
return p.DiffResponse{}, err
}
Expand Down
32 changes: 24 additions & 8 deletions infer/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ import (
"strings"

"github.com/hashicorp/go-multierror"
provider "github.com/pulumi/pulumi-go-provider"
"github.com/pulumi/pulumi/pkg/v3/codegen/schema"
"github.com/pulumi/pulumi/sdk/v3/go/common/resource"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
"golang.org/x/net/context"

"github.com/pulumi/pulumi-go-provider/infer/types"
"github.com/pulumi/pulumi-go-provider/internal/introspect"
Expand Down Expand Up @@ -83,18 +85,18 @@ func getAnnotated(t reflect.Type) introspect.Annotator {
return ret
}

func getResourceSchema[R, I, O any](isComponent bool) (schema.ResourceSpec, multierror.Error) {
func getResourceSchema[R, I, O any](ctx context.Context, isComponent bool) (schema.ResourceSpec, multierror.Error) {
var r R
var errs multierror.Error
descriptions := getAnnotated(reflect.TypeOf(r))

properties, required, err := propertyListFromType(reflect.TypeOf(new(O)), isComponent)
properties, required, err := propertyListFromType(ctx, reflect.TypeOf(new(O)), isComponent)
if err != nil {
var o O
errs.Errors = append(errs.Errors, fmt.Errorf("could not serialize output type %T: %w", o, err))
}

inputProperties, requiredInputs, err := propertyListFromType(reflect.TypeOf(new(I)), isComponent)
inputProperties, requiredInputs, err := propertyListFromType(ctx, reflect.TypeOf(new(I)), isComponent)
if err != nil {
var i I
errs.Errors = append(errs.Errors, fmt.Errorf("could not serialize input type %T: %w", i, err))
Expand All @@ -112,18 +114,32 @@ func getResourceSchema[R, I, O any](isComponent bool) (schema.ResourceSpec, mult
}, errs
}

// serializeTypeAsPropertyType is called often and we want to avoid repeated identical warnings.
var warnedAboutAsset = false

func warnAboutAsset(ctx context.Context) {
if warnedAboutAsset {
return
}
provider.GetLogger(ctx).WarningStatus(
"Please use pulumi-go-provider's types.AssetOrArchive type instead of resource.Asset or resource.Archive. For context, see https://github.com/pulumi/pulumi-go-provider/issues/237.")
warnedAboutAsset = true
}

func serializeTypeAsPropertyType(
t reflect.Type, indicatePlain bool, extType *introspect.ExplicitType,
ctx context.Context, t reflect.Type, indicatePlain bool, extType *introspect.ExplicitType,
) (schema.TypeSpec, error) {
for t.Kind() == reflect.Pointer {
t = t.Elem()
}
if t == reflect.TypeOf(resource.Asset{}) {
warnAboutAsset(ctx)
return schema.TypeSpec{
Ref: "pulumi.json#/Asset",
}, nil
}
if t == reflect.TypeOf(resource.Archive{}) {
warnAboutAsset(ctx)
return schema.TypeSpec{
Ref: "pulumi.json#/Archive",
}, nil
Expand Down Expand Up @@ -165,7 +181,7 @@ func serializeTypeAsPropertyType(
if t.Key().Kind() != reflect.String {
return schema.TypeSpec{}, fmt.Errorf("map keys must be strings, found %s", t.Key().String())
}
el, err := serializeTypeAsPropertyType(t.Elem(), indicatePlain, extType)
el, err := serializeTypeAsPropertyType(ctx, t.Elem(), indicatePlain, extType)
if err != nil {
return schema.TypeSpec{}, err
}
Expand All @@ -174,7 +190,7 @@ func serializeTypeAsPropertyType(
AdditionalProperties: &el,
}, nil
case reflect.Array, reflect.Slice:
el, err := serializeTypeAsPropertyType(t.Elem(), indicatePlain, extType)
el, err := serializeTypeAsPropertyType(ctx, t.Elem(), indicatePlain, extType)
if err != nil {
return schema.TypeSpec{}, err
}
Expand Down Expand Up @@ -247,7 +263,7 @@ func underlyingType(t reflect.Type) (reflect.Type, bool, error) {
return t, isOutputType || isInputType, nil
}

func propertyListFromType(typ reflect.Type, indicatePlain bool) (
func propertyListFromType(ctx context.Context, typ reflect.Type, indicatePlain bool) (
props map[string]schema.PropertySpec, required []string, err error) {
for typ.Kind() == reflect.Pointer {
typ = typ.Elem()
Expand All @@ -267,7 +283,7 @@ func propertyListFromType(typ reflect.Type, indicatePlain bool) (
if tags.Internal {
continue
}
serialized, err := serializeTypeAsPropertyType(fieldType, indicatePlain, tags.ExplicitRef)
serialized, err := serializeTypeAsPropertyType(ctx, fieldType, indicatePlain, tags.ExplicitRef)
if err != nil {
return nil, nil, fmt.Errorf("invalid type '%s' on '%s.%s': %w", fieldType, typ, field.Name, err)
}
Expand Down
5 changes: 3 additions & 2 deletions infer/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package infer

import (
"context"
"errors"
"fmt"
"reflect"
Expand Down Expand Up @@ -245,7 +246,7 @@ func crawlTypes[T any](crawler Crawler) error {
}

// registerTypes recursively examines fields of T, calling reg on the schematized type when appropriate.
func registerTypes[T any](reg schema.RegisterDerivativeType) error {
func registerTypes[T any](ctx context.Context, reg schema.RegisterDerivativeType) error {
crawler := func(
t reflect.Type, isReference bool, info *introspect.FieldTag,
parent, field string,
Expand Down Expand Up @@ -285,7 +286,7 @@ func registerTypes[T any](reg schema.RegisterDerivativeType) error {
return false, err
}
if t.Kind() == reflect.Struct {
spec, err := objectSchema(t)
spec, err := objectSchema(ctx, t)
if err != nil {
return false, err
}
Expand Down
2 changes: 1 addition & 1 deletion infer/types/asset.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const ArchiveSignature = "195f3948f6769324d4661e1e245f3a4d"

// AssetOrArchive is a union type that can represent either an Asset or an Archive.
// Setting both fields to non-nil values is an error.
// This type exists to accomodate the semantics of the core Pulumi SDK's Asset type,
// This type exists to accomomdate the semantics of the core Pulumi SDK's Asset type,
// which is also a union of Asset and Archive.
type AssetOrArchive struct {
Asset *resource.Asset `pulumi:"a9e28acb8ab501f883219e7c9f624fb6,optional"`
Expand Down
13 changes: 7 additions & 6 deletions infer/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package infer

import (
"context"
"reflect"
"testing"

Expand Down Expand Up @@ -162,7 +163,7 @@ func TestCrawlTypes(t *testing.T) {
m[typ.String()] = spec
return true
}
err := registerTypes[Foo](reg)
err := registerTypes[Foo](context.Background(), reg)
assert.NoError(t, err)

assert.Equal(t,
Expand Down Expand Up @@ -228,10 +229,10 @@ func TestReservedFields(t *testing.T) {
reg := func(tokens.Type, pschema.ComplexTypeSpec) bool {
return true
}
err := registerTypes[outer](reg)
err := registerTypes[outer](context.Background(), reg)
assert.NoError(t, err, "id isn't reserved on nested fields")

err = registerTypes[inner](reg)
err = registerTypes[inner](context.Background(), reg)
assert.ErrorContains(t, err, `"id" is a reserved field name`)
}

Expand All @@ -247,7 +248,7 @@ func noOpRegister() schema.RegisterDerivativeType {
func registerOk[T any]() func(t *testing.T) {
return func(t *testing.T) {
t.Parallel()
err := registerTypes[T](noOpRegister())
err := registerTypes[T](context.Background(), noOpRegister())
assert.NoError(t, err)
}
}
Expand All @@ -268,7 +269,7 @@ func TestInvalidOptionalProperty(t *testing.T) {

t.Run("invalid optional enum", func(t *testing.T) {
t.Parallel()
err := registerTypes[invalidContainsOptionalEnum](noOpRegister())
err := registerTypes[invalidContainsOptionalEnum](context.Background(), noOpRegister())

var actual optionalNeedsPointerError
if assert.ErrorAs(t, err, &actual) {
Expand All @@ -290,7 +291,7 @@ func TestInvalidOptionalProperty(t *testing.T) {

t.Run("invalid optional struct", func(t *testing.T) {
t.Parallel()
err := registerTypes[invalidContainsOptionalStruct](noOpRegister())
err := registerTypes[invalidContainsOptionalStruct](context.Background(), noOpRegister())

var actual optionalNeedsPointerError
if assert.ErrorAs(t, err, &actual) {
Expand Down
22 changes: 11 additions & 11 deletions middleware/schema/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ type Resource interface {
// Return the Resource's schema definition. The passed in function should be called on
// types transitively referenced by the resource. See the documentation of
// RegisterDerivativeType for more details.
GetSchema(RegisterDerivativeType) (schema.ResourceSpec, error)
GetSchema(context.Context, RegisterDerivativeType) (schema.ResourceSpec, error)
}

// A Function that can generate its own schema definition.
Expand All @@ -57,7 +57,7 @@ type Function interface {
// Return the Function's schema definition. The passed in function should be called on
// types transitively referenced by the function. See the documentation of
// RegisterDerivativeType for more details.
GetSchema(RegisterDerivativeType) (schema.FunctionSpec, error)
GetSchema(context.Context, RegisterDerivativeType) (schema.FunctionSpec, error)
}

type cache struct {
Expand Down Expand Up @@ -309,13 +309,13 @@ func (s *state) generateSchema(ctx context.Context) (schema.PackageSpec, error)
pkg.Types[tkString] = renamePackage(t, info.PackageName, s.ModuleMap)
return true
}
errs := addElements(s.Resources, pkg.Resources, info.PackageName, registerDerivative, s.ModuleMap)
e := addElements(s.Invokes, pkg.Functions, info.PackageName, registerDerivative, s.ModuleMap)
errs := addElements(ctx, s.Resources, pkg.Resources, info.PackageName, registerDerivative, s.ModuleMap)
e := addElements(ctx, s.Invokes, pkg.Functions, info.PackageName, registerDerivative, s.ModuleMap)
errs.Errors = append(errs.Errors, e.Errors...)

if s.Provider != nil {
_, prov, err := addElement[Resource, schema.ResourceSpec](
info.PackageName, registerDerivative, s.ModuleMap, s.Provider)
ctx, info.PackageName, registerDerivative, s.ModuleMap, s.Provider)
if err != nil {
errs.Errors = append(errs.Errors, err)
}
Expand All @@ -333,15 +333,15 @@ func (s *state) generateSchema(ctx context.Context) (schema.PackageSpec, error)

type canGetSchema[T any] interface {
GetToken() (tokens.Type, error)
GetSchema(RegisterDerivativeType) (T, error)
GetSchema(context.Context, RegisterDerivativeType) (T, error)
}

func addElements[T canGetSchema[S], S any](els []T, m map[string]S,
pkgName string, reg RegisterDerivativeType,
func addElements[T canGetSchema[S], S any](ctx context.Context,
els []T, m map[string]S, pkgName string, reg RegisterDerivativeType,
modMap map[tokens.ModuleName]tokens.ModuleName) multierror.Error {
errs := multierror.Error{}
for _, f := range els {
tk, element, err := addElement[T, S](pkgName, reg, modMap, f)
tk, element, err := addElement[T, S](ctx, pkgName, reg, modMap, f)
if err != nil {
errs.Errors = append(errs.Errors, err)
continue
Expand All @@ -351,15 +351,15 @@ func addElements[T canGetSchema[S], S any](els []T, m map[string]S,
return errs
}

func addElement[T canGetSchema[S], S any](pkgName string, reg RegisterDerivativeType,
func addElement[T canGetSchema[S], S any](ctx context.Context, pkgName string, reg RegisterDerivativeType,
modMap map[tokens.ModuleName]tokens.ModuleName, f T) (tokens.Type, S, error) {
var s S
tk, err := f.GetToken()
if err != nil {
return "", s, err
}
tk = assignTo(tk, pkgName, modMap)
fun, err := f.GetSchema(reg)
fun, err := f.GetSchema(ctx, reg)
if err != nil {
return "", s, fmt.Errorf("failed to get schema for '%s': %w", tk, err)
}
Expand Down
Loading

0 comments on commit fbd137e

Please sign in to comment.