pulumi/pkg/tools/cidlc/types.go
joeduffy 335ea01275 Implement archives
Our initial implementation of assets was intentionally naive, because
they were limited to single-file assets.  However, it turns out that for
real scenarios (like lambdas), we want to support multi-file assets.

In this change, we introduce the concept of an Archive.  An archive is
what the term classically means: a collection of files, addressed as one.
For now, we support three kinds: tarfile archives (*.tar), gzip-compressed
tarfile archives (*.tgz, *.tar), and normal zipfile archives (*.zip).

There is a fair bit of library support for manipulating Archives as a
logical collection of Assets.  I've gone to great length to avoid making
copies, however, sometimes it is unavoidable (for example, when sizes
are required in order to emit offsets).  This is also complicated by the
fact that the AWS libraries often want seekable streams, if not actual
raw contiguous []byte slices.
2017-04-30 12:37:24 -07:00

101 lines
2.6 KiB
Go

// Copyright 2017 Pulumi, Inc. All rights reserved.
package cidlc
import (
"go/types"
"reflect"
"github.com/pulumi/coconut/pkg/resource/idl"
"github.com/pulumi/coconut/pkg/util/contract"
)
func IsPrimitive(t types.Type) bool {
if basic, isbasic := t.(*types.Basic); isbasic {
switch basic.Kind() {
case types.Bool, types.Float64, types.String:
return true
}
}
return false
}
// IsEntity checks whether a type is an entity that can be used by-reference (asset, resource, etc).
func IsEntity(obj *types.TypeName, t types.Type) bool {
if res, _ := IsResource(obj, t); res {
return true
}
spec, _ := IsSpecial(obj)
return spec
}
// IsResource checks whether a type is a special IDL resource. If yes, it returns true for the first boolean, and the
// second boolean indicates whether the resource is named or not.
func IsResource(obj *types.TypeName, t types.Type) (bool, bool) {
contract.Assert(obj != nil)
// If this is a resource type itself, then we're done.
if isres, isname := IsSpecialResource(obj); isres {
return isres, isname
}
// If a named type, fetch the underlying.
if n, is := t.(*types.Named); is {
t = n.Underlying()
}
if s, is := t.(*types.Struct); is {
// Otherwise, it's a resource if it has an embedded resource field.
for i := 0; i < s.NumFields(); i++ {
fld := s.Field(i)
if fld.Anonymous() {
if named, ok := fld.Type().(*types.Named); ok {
if isres, isname := IsSpecialResource(named.Obj()); isres {
return isres, isname
}
}
}
}
}
return false, false
}
type SpecialType int
const (
NotSpecialType = iota
SpecialResourceType
SpecialNamedResourceType
SpecialAssetType
SpecialArchiveType
)
var (
idlArchiveType = reflect.TypeOf(idl.Archive{})
idlAssetType = reflect.TypeOf(idl.Asset{})
idlResourceType = reflect.TypeOf(idl.Resource{})
idlNamedResourceType = reflect.TypeOf(idl.NamedResource{})
)
func IsSpecial(obj *types.TypeName) (bool, SpecialType) {
if obj != nil && obj.Pkg().Path() == idlResourceType.PkgPath() {
switch obj.Name() {
case idlArchiveType.Name():
return true, SpecialArchiveType
case idlAssetType.Name():
return true, SpecialAssetType
case idlResourceType.Name():
return true, SpecialResourceType
case idlNamedResourceType.Name():
return true, SpecialNamedResourceType
}
}
return false, NotSpecialType
}
func IsSpecialResource(obj *types.TypeName) (bool, bool) {
spec, kind := IsSpecial(obj)
isres := (spec && kind == SpecialResourceType)
isnamed := (spec && kind == SpecialNamedResourceType)
return isres || isnamed, isnamed
}