diff --git a/Gopkg.lock b/Gopkg.lock
index 9c57a9085..ea157222b 100644
--- a/Gopkg.lock
+++ b/Gopkg.lock
@@ -210,12 +210,6 @@
packages = ["collate","collate/build","internal/colltab","internal/gen","internal/tag","internal/triegen","internal/ucd","language","secure/bidirule","transform","unicode/bidi","unicode/cldr","unicode/norm","unicode/rangetable"]
revision = "88f656faf3f37f690df1a32515b479415e1a6769"
-[[projects]]
- branch = "master"
- name = "golang.org/x/tools"
- packages = ["go/ast/astutil","go/buildutil","go/loader"]
- revision = "05e91d06384e3a4eb0aba75560d254b8d5a7b431"
-
[[projects]]
branch = "master"
name = "google.golang.org/genproto"
@@ -249,6 +243,6 @@
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
- inputs-digest = "70b9f724d4635dd578c12a951ddcfe2315a569443822eeb162fbba2cbcf7627e"
+ inputs-digest = "d03e73559b3e1af69207eeae805c237c8bef6f836a2322e883d428e0abef1810"
solver-name = "gps-cdcl"
solver-version = 1
diff --git a/Makefile b/Makefile
index 1d202b931..96c2eec6e 100644
--- a/Makefile
+++ b/Makefile
@@ -15,7 +15,6 @@ TEST_FAST_TIMEOUT := 2m
build::
go install -ldflags "-X github.com/pulumi/pulumi/pkg/version.Version=${VERSION}" ${PROJECT}
- go install -ldflags "-X github.com/pulumi/pulumi/pkg/version.Version=${VERSION}" ${PROJECT}/cmd/lumidl
install::
GOBIN=$(PULUMI_BIN) go install -ldflags "-X github.com/pulumi/pulumi/pkg/version.Version=${VERSION}" ${PROJECT}
diff --git a/build.proj b/build.proj
index 5529b4c8d..3fc87c588 100644
--- a/build.proj
+++ b/build.proj
@@ -62,7 +62,7 @@
-
+
@@ -105,7 +105,6 @@
-
diff --git a/cmd/lumidl/README.md b/cmd/lumidl/README.md
deleted file mode 100644
index 86c27954a..000000000
--- a/cmd/lumidl/README.md
+++ /dev/null
@@ -1,52 +0,0 @@
-# Lumi IDL
-
-The Lumi IDL compiler (LumIDL) compiles an Go-based IDL into Lumi metadata and packages.
-
-## IDL
-
-The compiler, `lumidl`, accepts a subset of Go. Please refer to [the IDL design document](/docs/idl.md) for details.
-
-## Providers
-
-The primary use case for Lumi IDL is to author resource packages and providers. A resource package is a low level
-Lumi package with metadata associated with a set of resource type definitions. Its associated provider is a dynamic
-plugin that implements the behavior associated with those resources, their CRUD functions, and operational semantics.
-
-The LumIDL toolset cuts down on boilerplate and makes it easy to author new resource packages and providers.
-
-## Building
-
-To build the Lumi IDL compiler, run
-
- $ go install github.com/pulumi/pulumi/cmd/lumidl
-
-from an enlistment with a proper `GOPATH` set.
-
-## Running
-
-To generate code, run:
-
- $ lumidl pkg-name idl-path [flags]
-
-where the `pkg-name` is the name of the target Lumi package, `idl-path` is a path to a directory containing IDL, and
-`flags` are an optional set of flags. All `*.go` files in the target directory are parsed and processed as IDL. To
-recursively fetch sub-packages, pass the `--recursive` (or `-r`) flag.
-
-The output includes the following:
-
-* A Lumi package in LumiJS, containing resource definitions.
-* An RPC package in Go to aid in the creation of a resource provider, containing:
- - A base resource provider that handles marshaling goo at the edges.
- - A marshalable type for each resource type (used for dynamic plugin serialization).
-
-The two flags, `--out-pack` and `--out-rpc` control if and where the output will be generated, respectively. It is
-possible to specify just one or the other, or you can generate both simultaneously.
-
-By default, the IDL Go package is inferred from a combination of `idl-path` and `GOPATH`. This is used to generate
-inter- and intra-package references. If you are generating RPC code, that too is inferred, based on `--out-rpc` and
-`GOPATH`. In the event you are running outside of a Go workspace (where `GOPATH` is not set), or need to customize
-these, the packages can be set by hand using the flags `--pkg-base-idl` and `--pkg-base-rpc`, respectively.
-
-After generating the code and implementing behavior associated with the resource in the provider, the Lumi package
-may then be distributed to consumers using LumiPy, LumiRu, LumiJS, and other LumiLangs.
-
diff --git a/cmd/lumidl/lumidl.go b/cmd/lumidl/lumidl.go
deleted file mode 100644
index e053d0fab..000000000
--- a/cmd/lumidl/lumidl.go
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2016-2017, Pulumi Corporation. All rights reserved.
-
-package main
-
-import (
- "github.com/golang/glog"
- "github.com/spf13/cobra"
-
- "github.com/pulumi/pulumi/pkg/tokens"
- "github.com/pulumi/pulumi/pkg/tools/lumidl"
- "github.com/pulumi/pulumi/pkg/util/cmdutil"
-)
-
-func NewIDLCCmd() *cobra.Command {
- var logToStderr bool
- var outPack string
- var outRPC string
- var pkgBaseIDL string
- var pkgBaseRPC string
- var quiet bool
- var recursive bool
- var verbose int
- cmd := &cobra.Command{
- Use: "lumidl pkg-name idl-path",
- Short: "The Lumi IDL compiler generates Lumi metadata and RPC stubs from IDL written in Go",
- Long: "The Lumi IDL compiler generates Lumi metadata and RPC stubs from IDL written in Go.\n" +
- "\n" +
- "The tool accepts a subset of Go types and produces packages that can be consumed by\n" +
- "ordinary Lumi programs and libraries in any language. The pkg-name argument\n" +
- "controls the output package name and idl-path is the path to the IDL source code.\n" +
- "\n" +
- "The --out-pack and --out-rpc flags indicate where generated code is to be saved,\n" +
- "and pkg-base-idl and --pkg-base-rpc may be used to override the default inferred Go\n" +
- "package names (which, by default, are based on your GOPATH).",
- PersistentPreRun: func(cmd *cobra.Command, args []string) {
- cmdutil.InitLogging(logToStderr, verbose, true)
- },
- Args: cmdutil.ExactArgs(2),
- Run: cmdutil.RunFunc(func(cmd *cobra.Command, args []string) error {
- // Now pass the arguments and compile the package.
- name := args[0] // the name of the Lumi package.
- path := args[1] // the path to the IDL directory that is compiled recursively.
- return lumidl.Compile(lumidl.CompileOptions{
- Name: tokens.PackageName(name),
- PkgBaseIDL: pkgBaseIDL,
- PkgBaseRPC: pkgBaseRPC,
- OutPack: outPack,
- OutRPC: outRPC,
- Quiet: quiet,
- Recursive: recursive,
- }, path)
- }),
- PersistentPostRun: func(cmd *cobra.Command, args []string) {
- glog.Flush()
- },
- }
-
- cmd.PersistentFlags().BoolVar(
- &logToStderr, "logtostderr", false, "Log to stderr instead of to files")
- cmd.PersistentFlags().BoolVarP(
- &recursive, "recursive", "r", false, "Recursively generate code for all sub-packages in the target")
- cmd.PersistentFlags().StringVar(
- &outPack, "out-pack", "", "Save generated package metadata to this directory")
- cmd.PersistentFlags().StringVar(
- &outRPC, "out-rpc", "", "Save generated RPC provider stubs to this directory")
- cmd.PersistentFlags().StringVar(
- &pkgBaseIDL, "pkg-base-idl", "", "Override the base URL where the IDL package is published")
- cmd.PersistentFlags().StringVar(
- &pkgBaseRPC, "pkg-base-rpc", "", "Override the base URL where the RPC package is published")
- cmd.PersistentFlags().BoolVarP(
- &quiet, "quiet", "q", false, "Suppress non-error output progress messages")
- cmd.PersistentFlags().IntVarP(
- &verbose, "verbose", "v", 0, "Enable verbose logging (e.g., v=3); anything >3 is very verbose")
-
- return cmd
-}
diff --git a/cmd/lumidl/main.go b/cmd/lumidl/main.go
deleted file mode 100644
index a13ab7606..000000000
--- a/cmd/lumidl/main.go
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2016-2017, Pulumi Corporation. All rights reserved.
-
-package main
-
-import (
- "fmt"
- "os"
-)
-
-func main() {
- if err := NewIDLCCmd().Execute(); err != nil {
- fmt.Fprintf(os.Stderr, "An error occurred: %v\n", err)
- os.Exit(-1)
- }
-}
diff --git a/pkg/tools/lumidl/check.go b/pkg/tools/lumidl/check.go
deleted file mode 100644
index 338ff4d4f..000000000
--- a/pkg/tools/lumidl/check.go
+++ /dev/null
@@ -1,389 +0,0 @@
-// Copyright 2016-2017, Pulumi Corporation. All rights reserved.
-
-package lumidl
-
-import (
- "go/ast"
- "go/types"
- "path/filepath"
- "reflect"
-
- "github.com/pkg/errors"
- "golang.org/x/tools/go/loader"
-
- "github.com/pulumi/pulumi/pkg/diag"
- "github.com/pulumi/pulumi/pkg/tokens"
- "github.com/pulumi/pulumi/pkg/util/cmdutil"
- "github.com/pulumi/pulumi/pkg/util/contract"
-)
-
-type Checker struct {
- Root string
- Program *loader.Program
- EnumValues map[types.Type][]string
-}
-
-func NewChecker(root string, prog *loader.Program) *Checker {
- return &Checker{
- Root: root,
- Program: prog,
- }
-}
-
-// diag produces a nice diagnostic location (document+position) from a Go element. It should be used for all output
-// messages to enable easy correlation with the source IDL artifact that triggered an error.
-func (chk *Checker) diag(elem goPos) diag.Diagable {
- return goDiag(chk.Program, elem, chk.Root)
-}
-
-// Check analyzes a Go program, ensures that it is valid as an IDL, and classifies all of the types that it
-// encounters. These classifications are returned. If problems are encountered, diagnostic messages will be output
-// and the returned error will be non-nil.
-func (chk *Checker) Check(name tokens.PackageName, pkginfo *loader.PackageInfo) (*Package, error) {
- ok := true
-
- // First just create a list of the constants and types so we can visit them in the right order. Also maintain a
- // file map so that we can recover the AST information later on (required for import processing, etc).
- var goconsts []*types.Const
- var gotypes []*types.TypeName
-
- // Enumerate the scope and classify all objects.
- scope := pkginfo.Pkg.Scope()
- for _, objname := range scope.Names() {
- obj := scope.Lookup(objname)
- switch o := obj.(type) {
- case *types.Const:
- goconsts = append(goconsts, o)
- case *types.TypeName:
- gotypes = append(gotypes, o)
- default:
- ok = false
- cmdutil.Diag().Errorf(
- diag.Message("%v is an unrecognized Go declaration type: %v").At(chk.diag(obj)),
- objname, reflect.TypeOf(obj))
- }
- }
-
- // Start building a package to return.
- pkg := NewPackage(name, chk.Program, pkginfo)
- oldenums := chk.EnumValues
- chk.EnumValues = make(map[types.Type][]string)
- defer (func() { chk.EnumValues = oldenums })()
-
- getfile := func(path string) *File {
- // If the file exists, fetch it.
- if file, has := pkg.Files[path]; has {
- return file
- }
- // Otherwise, find the AST node, and create a new object.
- for _, fileast := range pkginfo.Files {
- if rel := RelFilename(chk.Root, chk.Program, fileast); rel == path {
- mod := string(name) + ":"
- if ext := filepath.Ext(rel); ext != "" {
- mod += rel[:len(rel)-len(ext)]
- } else {
- mod += rel
- }
- file := NewFile(path, tokens.Module(mod), fileast)
- pkg.Files[path] = file
- return file
- }
- }
- contract.Failf("Missing file AST for path %v", path)
- return nil
- }
- getdecl := func(file *File, obj types.Object) ast.Decl {
- for _, decl := range file.Node.Decls {
- if gdecl, isgdecl := decl.(*ast.GenDecl); isgdecl {
- for _, spec := range gdecl.Specs {
- switch sp := spec.(type) {
- case *ast.ImportSpec:
- // ignore
- case *ast.TypeSpec:
- if sp.Name.Name == obj.Name() {
- return decl
- }
- case *ast.ValueSpec:
- for _, name := range sp.Names {
- if name.Name == obj.Name() {
- return decl
- }
- }
- default:
- contract.Failf("Unrecognized GenDecl Spec type: %v", reflect.TypeOf(sp))
- }
- }
- }
- }
- contract.Failf("Missing object AST decl for %v in %v", obj.Name(), file)
- return nil
- }
-
- // Now visit all constants so that we can have them handy as we visit enum types.
- for _, goconst := range goconsts {
- path := RelFilename(chk.Root, chk.Program, goconst)
- file := getfile(path)
- decl := getdecl(file, goconst)
- if c, cok := chk.CheckConst(goconst, file, decl); cok {
- nm := tokens.Name(goconst.Name())
- pkg.AddMember(file, nm, c)
- } else {
- contract.Assert(!cmdutil.Diag().Success())
- ok = false
- }
- }
-
- // Next, visit all the types.
- for _, gotype := range gotypes {
- path := RelFilename(chk.Root, chk.Program, gotype)
- file := getfile(path)
- decl := getdecl(file, gotype)
- if t, tok := chk.CheckType(gotype, file, decl); tok {
- nm := tokens.Name(gotype.Name())
- pkg.AddMember(file, nm, t)
- } else {
- contract.Assert(!cmdutil.Diag().Success())
- ok = false
- }
- }
-
- if !ok {
- contract.Assert(!cmdutil.Diag().Success())
- return nil, errors.New("one or more problems with the input IDL were found; skipping code-generation")
- }
-
- return pkg, nil
-}
-
-func (chk *Checker) CheckConst(c *types.Const, file *File, decl ast.Decl) (*Const, bool) {
- pt := c.Type()
- var t types.Type
- if IsPrimitive(pt) {
- // A primitive, just use it as-is.
- t = pt
- } else if named, isnamed := pt.(*types.Named); isnamed {
- // A constant of a type alias. This is how IDL enums are defined, so interpret it as such.
- if basic, isbasic := named.Underlying().(*types.Basic); isbasic && basic.Kind() == types.String {
- // Use this type and remember the enum value.
- t = pt
- chk.EnumValues[t] = append(chk.EnumValues[t], c.Val().String())
- } else {
- cmdutil.Diag().Errorf(
- diag.Message("enums must be string-backed; %v has type %v").At(chk.diag(decl)),
- c, named,
- )
- }
- } else {
- cmdutil.Diag().Errorf(
- diag.Message("only constants of valid primitive types (bool, float64, number, or aliases) supported").At(
- chk.diag(decl)))
- }
-
- if t != nil {
- return &Const{
- member: member{
- tok: tokens.ModuleMember(string(file.Module) + ":" + c.Name()),
- exported: c.Exported(),
- pos: c.Pos(),
- },
- Type: pt,
- Value: c.Val(),
- }, true
- }
-
- return nil, false
-}
-
-func (chk *Checker) CheckType(t *types.TypeName, file *File, decl ast.Decl) (Member, bool) {
- memb := member{
- tok: tokens.ModuleMember(string(file.Module) + ":" + t.Name()),
- exported: t.Exported(),
- pos: t.Pos(),
- }
- switch typ := t.Type().(type) {
- case *types.Named:
- switch s := typ.Underlying().(type) {
- case *types.Basic:
- // A type alias, possibly interpreted as an enum if there are constants.
- if IsPrimitive(s) {
- if vals, isenum := chk.EnumValues[typ]; isenum {
- // There are enum values defined, use them to create an enum type.
- return &Enum{
- member: memb,
- Values: vals,
- }, true
- }
- // Otherwise, this is a simple type alias.
- return &Alias{
- member: memb,
- target: s,
- }, true
- }
-
- cmdutil.Diag().Errorf(diag.Message(
- "type alias %v is not a valid IDL alias type (must be bool, float64, or string)").At(
- chk.diag(decl)))
- case *types.Map, *types.Slice:
- return &Alias{
- member: memb,
- target: s,
- }, true
- case *types.Struct:
- // A struct definition, possibly a resource. First, check that all the fields are supported types.
- isres := IsResource(t, s)
- if ok, props, opts := chk.CheckStructFields(typ.Obj(), s, isres); ok {
- // If a resource, return additional information.
- if isres {
- return &Resource{
- member: memb,
- s: s,
- props: props,
- popts: opts,
- }, true
- }
- // Otherwise, it's a plain old ordinary struct.
- return &Struct{
- member: memb,
- s: s,
- props: props,
- popts: opts,
- }, true
- }
- contract.Assert(!cmdutil.Diag().Success())
- default:
- cmdutil.Diag().Errorf(
- diag.Message("%v is an illegal underlying type: %v").At(chk.diag(decl)), s, reflect.TypeOf(s))
- }
- default:
- cmdutil.Diag().Errorf(
- diag.Message("%v is an illegal Go type kind: %v").At(chk.diag(decl)), t.Name(), reflect.TypeOf(typ))
- }
- return nil, false
-}
-
-// CheckStructFields ensures that a struct only contains valid "JSON-like" fields
-func (chk *Checker) CheckStructFields(t *types.TypeName, s *types.Struct,
- isres bool) (bool, []*types.Var, []PropertyOptions) {
- ok := true
- var allprops []*types.Var
- var allopts []PropertyOptions
- for i := 0; i < s.NumFields(); i++ {
- fld := s.Field(i)
- if fld.Anonymous() {
- // If an embedded structure, validate its fields deeply.
- anon := fld.Type().(*types.Named)
- embedded := anon.Underlying().(*types.Struct)
- isembres := IsResource(anon.Obj(), embedded)
- isok, props, opts := chk.CheckStructFields(anon.Obj(), embedded, isembres)
- if !isok {
- ok = false
- }
- allprops = append(allprops, props...)
- allopts = append(allopts, opts...)
- } else {
- allprops = append(allprops, fld)
- opts := ParsePropertyOptions(s.Tag(i))
- allopts = append(allopts, opts)
- if opts.Name == "" {
- ok = false
- cmdutil.Diag().Errorf(
- diag.Message("field %v.%v is missing a `pulumi:\"\"` tag directive").At(chk.diag(fld)),
- t.Name(), fld.Name())
- }
- if opts.Out && !isres {
- ok = false
- cmdutil.Diag().Errorf(
- diag.Message("field %v.%v is marked `out` but is not a resource property").At(chk.diag(fld)),
- t.Name(), fld.Name())
- }
- if opts.Replaces && !isres {
- ok = false
- cmdutil.Diag().Errorf(
- diag.Message("field %v.%v is marked `replaces` but is not a resource property").At(chk.diag(fld)),
- t.Name(), fld.Name())
- }
- if _, isptr := fld.Type().(*types.Pointer); !isptr && opts.Optional {
- ok = false
- cmdutil.Diag().Errorf(
- diag.Message("field %v.%v is marked `optional` but is not a pointer in the IDL").At(chk.diag(fld)),
- t.Name(), fld.Name())
- }
- if err := chk.CheckIDLType(fld.Type(), opts); err != nil {
- ok = false
- cmdutil.Diag().Errorf(
- diag.Message("field %v.%v is an not a legal IDL type: %v").At(chk.diag(fld)),
- t.Name(), fld.Name(), err)
- }
- }
- }
- return ok, allprops, allopts
-}
-
-func (chk *Checker) CheckIDLType(t types.Type, opts PropertyOptions) error {
- // Only these types are legal:
- // - Primitives: bool, float64, string
- // - Other structs
- // - Pointers to any of the above (if-and-only-if an optional property)
- // - Pointers to other resource types (capabilities)
- // - Arrays of the above things
- // - Maps with string keys and any of the above as values
- switch ft := t.(type) {
- case *types.Basic:
- if !IsPrimitive(ft) {
- return errors.Errorf("bad primitive type %v; must be bool, float64, or string", ft)
- }
- case *types.Interface:
- // interface{} is fine and is interpreted as a weakly typed map.
- return nil
- case *types.Named:
- switch ut := ft.Underlying().(type) {
- case *types.Basic:
- // A named type alias of a primitive type. Ensure it is legal.
- if !IsPrimitive(ut) {
- return errors.Errorf(
- "typedef %v backed by bad primitive type %v; must be bool, float64, or string", ft, ut)
- }
- case *types.Struct:
- // Struct types are okay so long as they aren't entities (these are required to be pointers).
- if isent := IsEntity(ft.Obj(), ut); isent {
- return errors.Errorf("type %v cannot be referenced by-value; must be a pointer", ft)
- }
- default:
- return errors.Errorf("bad named field type: %v", reflect.TypeOf(ut))
- }
- case *types.Pointer:
- // A pointer is OK so long as the field is either optional or an entity type (asset, resource, etc).
- if !opts.Optional && !opts.In && !opts.Out {
- elem := ft.Elem()
- var ok bool
- if named, isnamed := elem.(*types.Named); isnamed {
- ok = IsEntity(named.Obj(), named)
- }
- if !ok {
- return errors.New("bad pointer; must be optional or a resource type")
- }
- }
- case *types.Map:
- // A map is OK so long as its key is a string (or string-backed type) and its element type is okay.
- isstr := false
- switch kt := ft.Key().(type) {
- case *types.Basic:
- isstr = (kt.Kind() == types.String)
- case *types.Named:
- if bt, isbt := kt.Underlying().(*types.Basic); isbt {
- isstr = (bt.Kind() == types.String)
- }
- }
- if !isstr {
- return errors.Errorf("map index type %v must be a string (or string-backed typedef)", ft.Key())
- }
- return chk.CheckIDLType(ft.Elem(), PropertyOptions{})
-
- case *types.Slice:
- // A slice is OK so long as its element type is also OK.
- return chk.CheckIDLType(ft.Elem(), PropertyOptions{})
- default:
- contract.Failf("Unrecognized field type %v: %v", t, reflect.TypeOf(t))
- }
- return nil
-}
diff --git a/pkg/tools/lumidl/compile.go b/pkg/tools/lumidl/compile.go
deleted file mode 100644
index 4cafe790f..000000000
--- a/pkg/tools/lumidl/compile.go
+++ /dev/null
@@ -1,211 +0,0 @@
-// Copyright 2016-2017, Pulumi Corporation. All rights reserved.
-
-package lumidl
-
-import (
- "fmt"
- "go/parser"
- "go/types"
- "io/ioutil"
- "os"
- "path/filepath"
- "sort"
- "strings"
-
- "github.com/pkg/errors"
- "golang.org/x/tools/go/loader"
-
- "github.com/pulumi/pulumi/pkg/tokens"
-)
-
-type CompileOptions struct {
- Name tokens.PackageName // the package name.
- PkgBaseIDL string // the base Go package URL for the IDL input.
- PkgBaseRPC string // the base Go package URL for the RPC output.
- OutPack string // the package output location.
- OutRPC string // the RPC output location.
- Quiet bool // true to suppress innocuous output messages.
- Recursive bool // true to generate code for all sub-packages.
-}
-
-// Compile runs the Go compiler against an IDL project and then generates code for the resulting program.
-func Compile(opts CompileOptions, path string) error {
- // Ensure we are generating *something*.
- if opts.OutPack == "" && opts.OutRPC == "" {
- return errors.New("neither --out-pack nor --out-rpc specified; no code to generate")
- }
-
- // Adjust settings to their defaults and adjust any paths to be absolute.
- if path == "" {
- if wd, err := os.Getwd(); err == nil {
- path = wd
- }
- } else {
- if absPath, err := filepath.Abs(path); err == nil {
- path = absPath
- }
- }
- if opts.PkgBaseIDL == "" {
- // The default IDL package base is just the GOPATH package path for the target IDL path.
- pkgpath, err := goPackagePath(path)
- if err != nil {
- return err
- }
- opts.PkgBaseIDL = pkgpath
- }
- if opts.OutPack != "" {
- if outpack, err := filepath.Abs(opts.OutPack); err == nil {
- opts.OutPack = outpack
- }
- }
- if opts.OutRPC != "" {
- if outrpc, err := filepath.Abs(opts.OutRPC); err == nil {
- opts.OutRPC = outrpc
- }
-
- // If there is no package base, pick a default based on GOPATH.
- if opts.PkgBaseRPC == "" {
- // The default RPC package base, like the IDL package base, defaults to the GOPATH package path.
- pkgpath, err := goPackagePath(opts.OutRPC)
- if err != nil {
- return err
- }
- opts.PkgBaseRPC = pkgpath
- }
- }
-
- var inputs []string
- if opts.Recursive {
- inp, err := gatherGoPackages(path)
- if err != nil {
- return err
- }
- inputs = inp
- } else {
- inputs = []string{opts.PkgBaseIDL}
- }
-
- // First point the Go compiler at the target packages to compile. Note that this runs both parsing and semantic
- // analysis, and will yield an error if anything with the Go program is wrong.
- var conf loader.Config
- if _, err := conf.FromArgs(inputs, false); err != nil {
- return err
- }
- conf.ParserMode |= parser.ParseComments // ensure doc comments are retained.
- prog, err := conf.Load()
- if err != nil {
- return err
- }
-
- // Now create in-memory IDL packages, validating contents as we go. The result contains classified elements
- // such as resources, structs, enum types, and anything required in order to perform subsequent code-generation.
- chk := NewChecker(path, prog)
- var packgen *PackGenerator
- if out := opts.OutPack; out != "" {
- packgen = NewPackGenerator(prog, path, opts.PkgBaseIDL, out)
- }
- var rpcgen *RPCGenerator
- if out := opts.OutRPC; out != "" {
- rpcgen = NewRPCGenerator(path, opts.PkgBaseIDL, opts.PkgBaseRPC, out)
- }
-
- // Enumerate all packages (in a deterministic order).
- var pkgs []*types.Package
- for pkg := range prog.AllPackages {
- pkgs = append(pkgs, pkg)
- }
- sort.Slice(pkgs, func(i, j int) bool {
- return pkgs[i].Path() < pkgs[j].Path()
- })
- for _, pkg := range pkgs {
- // Only emit packages that are underneath the base IDL package.
- if !strings.HasPrefix(pkg.Path(), opts.PkgBaseIDL) {
- continue
- }
-
- pkginfo := prog.AllPackages[pkg]
- if !opts.Quiet {
- fmt.Printf("Processing package %v\n", pkginfo.Pkg.Path())
- }
-
- outpkg, err := chk.Check(opts.Name, pkginfo)
- if err != nil {
- return err
- }
-
- // Now generate the package output.
- if packgen != nil {
- if err = packgen.Generate(outpkg); err != nil {
- return err
- }
- }
-
- // Next generate the RPC stubs output.
- if rpcgen != nil {
- if err = rpcgen.Generate(outpkg); err != nil {
- return err
- }
- }
- }
-
- return nil
-}
-
-// goPackagePath takes a path to a filesystem location and returns its Go package path, based on GOPATH. Given a path
-// referring to a source location of the form, `$GOPATH/src/...`, the function returns the `...` part.
-func goPackagePath(path string) (string, error) {
- // Fetch the GOPATH; it must be set, else we bail out.
- gopath := os.Getenv("GOPATH")
- if gopath == "" {
- return "", errors.New("GOPATH is not set, so package paths cannot be inferred (see --pkg-base-x)")
- }
- gopath = filepath.Join(gopath, "src")
-
- // Now ensure that the package path is a proper subset within it.
- if !strings.HasPrefix(path, gopath+string(os.PathSeparator)) {
- return "", errors.Errorf(
- "Package root '%v' is not underneath $GOPATH/src, so its package cannot be inferred", path)
- }
-
- // Finally, strip off the GOPATH/src prefix, and return the remainder.
- return path[len(gopath)+1:], nil
-}
-
-// gatherGoPackages recurses into a given path and fetches all of its inferred Go packages. The algorithm considers
-// any sub-directory containing a *.go file, recursively, to be a package. It could, of course, be wrong.
-func gatherGoPackages(path string) ([]string, error) {
- var pkgs []string
-
- // First, if this path contains Go files, append it.
- var dirs []string
- hasGoFiles := false
- files, err := ioutil.ReadDir(path)
- if err != nil {
- return nil, err
- }
- for _, file := range files {
- if file.IsDir() {
- dirs = append(dirs, file.Name())
- } else if filepath.Ext(file.Name()) == ".go" {
- hasGoFiles = true
- }
- }
- if hasGoFiles {
- pkg, err := goPackagePath(path)
- if err != nil {
- return nil, err
- }
- pkgs = append(pkgs, pkg)
- }
-
- // Next, enumerate all directories recursively, to find all Go sub-packages.
- for _, dir := range dirs {
- subpkgs, err := gatherGoPackages(filepath.Join(path, dir))
- if err != nil {
- return nil, err
- }
- pkgs = append(pkgs, subpkgs...)
- }
-
- return pkgs, nil
-}
diff --git a/pkg/tools/lumidl/diag.go b/pkg/tools/lumidl/diag.go
deleted file mode 100644
index 0a085ee6e..000000000
--- a/pkg/tools/lumidl/diag.go
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2016-2017, Pulumi Corporation. All rights reserved.
-
-package lumidl
-
-import (
- "go/token"
- "path/filepath"
-
- "golang.org/x/tools/go/loader"
-
- "github.com/pulumi/pulumi/pkg/diag"
- "github.com/pulumi/pulumi/pkg/util/contract"
-)
-
-type goPos interface {
- Pos() token.Pos
-}
-
-// goDiag produces a diagnostics object out of a Go type artifact.
-func goDiag(prog *loader.Program, elem goPos, relto string) diag.Diagable {
- pos := prog.Fset.Position(elem.Pos())
- file := pos.Filename
- if relto != "" {
- var err error
- file, err = filepath.Rel(relto, file)
- contract.Assertf(err == nil, "error: %v", err)
- }
- return &goDiagable{
- doc: diag.NewDocument(file),
- loc: &diag.Location{
- Start: diag.Pos{
- Line: pos.Line,
- Column: pos.Column,
- },
- },
- }
-}
-
-type goDiagable struct {
- doc *diag.Document
- loc *diag.Location
-}
-
-func (d *goDiagable) Where() (*diag.Document, *diag.Location) {
- return d.doc, d.loc
-}
diff --git a/pkg/tools/lumidl/gen.go b/pkg/tools/lumidl/gen.go
deleted file mode 100644
index 88b3ddab1..000000000
--- a/pkg/tools/lumidl/gen.go
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2016-2017, Pulumi Corporation. All rights reserved.
-
-package lumidl
-
-import (
- "go/types"
- "path/filepath"
-
- "github.com/pulumi/pulumi/pkg/tools"
-)
-
-const lumidl = "the Lumi IDL Compiler (LUMIDL)" // used in generated files.
-
-// mirrorDirLayout ensures a target output directory contains the same layout as the input package.
-func mirrorDirLayout(pkg *Package, out string) error {
- for relpath := range pkg.Files {
- // Make the target file by concatening the output with the relative path, and ensure the directory exists.
- path := filepath.Join(out, relpath)
- if err := tools.EnsureFileDir(path); err != nil {
- return err
- }
- }
- return nil
-}
-
-func forEachField(t TypeMember, action func(*types.Var, PropertyOptions)) int {
- return forEachStructField(t.Struct(), t.PropertyOptions(), action)
-}
-
-func forEachStructField(s *types.Struct, opts []PropertyOptions, action func(*types.Var, PropertyOptions)) int {
- n := 0
- for i, j := 0, 0; i < s.NumFields(); i++ {
- fld := s.Field(i)
- if fld.Anonymous() {
- // For anonymous types, recurse.
- named := fld.Type().(*types.Named)
- embedded := named.Underlying().(*types.Struct)
- k := forEachStructField(embedded, opts[j:], action)
- j += k
- n += k
- } else {
- // For actual fields, invoke the action, and bump the counters.
- if action != nil {
- action(s.Field(i), opts[j])
- }
- j++
- n++
- }
- }
- return n
-}
diff --git a/pkg/tools/lumidl/gen_pack.go b/pkg/tools/lumidl/gen_pack.go
deleted file mode 100644
index 50def0796..000000000
--- a/pkg/tools/lumidl/gen_pack.go
+++ /dev/null
@@ -1,445 +0,0 @@
-// Copyright 2016-2017, Pulumi Corporation. All rights reserved.
-
-package lumidl
-
-import (
- "fmt"
- "go/types"
- "path/filepath"
- "reflect"
- "sort"
- "strings"
-
- "golang.org/x/tools/go/loader"
-
- "github.com/pulumi/pulumi/pkg/tokens"
- "github.com/pulumi/pulumi/pkg/tools"
- "github.com/pulumi/pulumi/pkg/util/contract"
-)
-
-// TODO[pulumi/pulumi#139]: preserve GoDocs in the generated code.
-
-type PackGenerator struct {
- Program *loader.Program // the compiled Go program.
- IDLRoot string // the path to the IDL on disk.
- IDLPkgBase string // the IDL's base package path.
- Out string // where to store the output package.
- CurrPkg *Package // the package currently being visited.
- CurrFile string // the file currently being visited.
- FileHadRes bool // true if the file had at least one resource.
- FileImports map[string]MemberImports // a map of imported package paths and members.
-}
-
-type MemberImports map[tokens.Name]string
-
-func NewPackGenerator(prog *loader.Program, root string, pkgBase string, out string) *PackGenerator {
- return &PackGenerator{
- Program: prog,
- IDLRoot: root,
- IDLPkgBase: pkgBase,
- Out: out,
- }
-}
-
-// Filename gets the source filename for a given Go element.
-func (g *PackGenerator) Filename(elem goPos) string {
- pos := elem.Pos()
- fset := g.Program.Fset
- return fset.Position(pos).Filename
-}
-
-// Generate generates a Lumi package's source code from a given compiled IDL program.
-func (g *PackGenerator) Generate(pkg *Package) error {
- // Ensure the directory structure exists in the target.
- if err := mirrorDirLayout(pkg, g.Out); err != nil {
- return err
- }
-
- // Install context about the current entity being visited.
- oldpkg, oldfile := g.CurrPkg, g.CurrFile
- g.CurrPkg = pkg
- defer (func() {
- g.CurrPkg, g.CurrFile = oldpkg, oldfile
- })()
-
- // Now walk through the package, file by file, and generate the contents.
- for relpath, file := range pkg.Files {
- var members []Member
- for _, nm := range file.MemberNames {
- members = append(members, file.Members[nm])
- }
- g.CurrFile = relpath
- path := filepath.Join(g.Out, relpath)
- if err := g.EmitFile(path, members); err != nil {
- return err
- }
- }
-
- return nil
-}
-
-func (g *PackGenerator) EmitFile(file string, members []Member) error {
- // Set up context.
- oldHadRes, oldImports := g.FileHadRes, g.FileImports
- g.FileHadRes, g.FileImports = false, make(map[string]MemberImports)
- defer (func() {
- g.FileHadRes = oldHadRes
- g.FileImports = oldImports
- })()
-
- // First, generate the body. This is required first so we know which imports to emit.
- body := g.genFileBody(members)
-
- // Next actually open up the file and emit the header, imports, and the body of the module.
- return g.emitFileContents(file, body)
-}
-
-func (g *PackGenerator) emitFileContents(file string, body string) error {
- // The output is TypeScript, so alter the extension.
- if dotindex := strings.LastIndex(file, "."); dotindex != -1 {
- file = file[:dotindex]
- }
- file += ".ts"
-
- // Open up a writer that overwrites whatever file contents already exist.
- w, err := tools.NewGenWriter(lumidl, file)
- if err != nil {
- return err
- }
- defer contract.IgnoreClose(w)
-
- // Emit a header into the file.
- w.EmitHeaderWarning()
- w.Writefmtln("/* tslint:disable:ordered-imports variable-name */")
-
- // If there are any resources, import the Lumi package.
- if g.FileHadRes {
- w.Writefmtln("import * as fabric from \"@pulumi/pulumi\";")
- w.Writefmtln("")
- }
- if len(g.FileImports) > 0 {
- // First, sort the imported package names, to ensure determinism.
- var ipkgs []string
- for ipkg := range g.FileImports {
- ipkgs = append(ipkgs, ipkg)
- }
- sort.Strings(ipkgs)
-
- for _, ipkg := range ipkgs {
- // Produce a map of filename to the members in that file that have been imported.
- importMap := make(map[string][]tokens.Name)
- for member, file := range g.FileImports[ipkg] {
- importMap[file] = append(importMap[file], member)
- }
-
- // Now sort them to ensure determinism.
- var importFiles []string
- for file := range importMap {
- importFiles = append(importFiles, file)
- }
- sort.Strings(importFiles)
-
- // Next, walk each imported file and import all members from within it.
- for _, file := range importFiles {
- // Make a relative import path from the current file.
- contract.Assertf(strings.HasPrefix(file, g.IDLRoot),
- "Inter-IDL package references not yet supported (%v is not part of %v)", file, g.IDLRoot)
- dir := filepath.Dir(g.CurrFile)
- relimp, err := filepath.Rel(dir, file[len(g.IDLRoot)+1:])
- contract.Assertf(err == nil, "Unexpected filepath.Rel error: %v", err)
- var impname string
- if strings.HasPrefix(relimp, ".") {
- impname = relimp
- } else {
- impname = "./" + relimp
- }
- if filepath.Ext(impname) != "" {
- lastdot := strings.LastIndex(impname, ".")
- impname = impname[:lastdot]
- }
-
- // Now produce a sorted list of imported members, again to ensure determinism.
- members := importMap[file]
- contract.Assert(len(members) > 0)
- sort.Slice(members, func(i, j int) bool {
- return string(members[i]) < string(members[j])
- })
-
- // Finally, go through and produce the import clause.
- w.Writefmt("import {")
- for i, member := range members {
- if i > 0 {
- w.Writefmt(", ")
- }
- w.Writefmt(string(member))
- }
- w.Writefmtln("} from \"%v\";", impname)
- }
- }
- w.Writefmtln("")
- }
-
- w.Writefmt("%v", body)
- return nil
-}
-
-func (g *PackGenerator) genFileBody(members []Member) string {
- // Accumulate the buffer in a string.
- w, err := tools.NewGenWriter(lumidl, "")
- contract.IgnoreError(err)
-
- // Now go ahead and emit the code for all members of this package.
- for i, m := range members {
- if i > 0 {
- // Allow aliases and consts to pile up without line breaks.
- _, isalias := m.(*Alias)
- _, isconst := m.(*Const)
- if (!isalias && !isconst) || reflect.TypeOf(m) != reflect.TypeOf(members[i-1]) {
- w.Writefmtln("")
- }
- }
- switch t := m.(type) {
- case *Alias:
- g.EmitAlias(w, t)
- case *Const:
- g.EmitConst(w, t)
- case *Enum:
- g.EmitEnum(w, t)
- case *Resource:
- g.EmitResource(w, t)
- case *Struct:
- g.EmitStruct(w, t)
- default:
- contract.Failf("Unrecognized package member type: %v", reflect.TypeOf(m))
- }
- }
-
- w.Writefmtln("")
- err = w.Flush()
- contract.IgnoreError(err)
- return w.Buffer()
-}
-
-func (g *PackGenerator) EmitAlias(w *tools.GenWriter, alias *Alias) {
- w.Writefmtln("export type %v = %v;",
- alias.Name(), g.GenTypeName(alias.Target(), NormalField))
-}
-
-func (g *PackGenerator) EmitConst(w *tools.GenWriter, konst *Const) {
- w.Writefmtln("export let %v: %v = %v;",
- konst.Name(), g.GenTypeName(konst.Type, NormalField), konst.Value.String())
-}
-
-func (g *PackGenerator) EmitEnum(w *tools.GenWriter, enum *Enum) {
- w.Writefmtln("export type %v =", enum.Name())
- contract.Assert(len(enum.Values) > 0)
- for i, value := range enum.Values {
- if i > 0 {
- w.Writefmtln(" |")
- }
- w.Writefmt(" %v", value)
- }
- w.Writefmtln(";")
-}
-
-func (g *PackGenerator) EmitResource(w *tools.GenWriter, res *Resource) {
- // Emit the full resource class definition, including constructor, etc.
- g.emitResourceClass(w, res)
- w.Writefmtln("")
-
- // Finally, emit an entire struct type for the args interface.
- g.emitStructType(w, res, res.Name()+tokens.Name("Args"))
-
- // Remember we had a resource in this file so we can import the right stuff.
- g.FileHadRes = true
-}
-
-func (g *PackGenerator) emitResourceClass(w *tools.GenWriter, res *Resource) {
- // Emit the class definition itself.
- name := res.Name()
- w.Writefmtln("export class %s extends fabric.Resource {", name)
-
- // First, emit all fields definitions.
- hasArgs := false
- hasRequiredArgs := false
- fn := forEachField(res, func(fld *types.Var, opt PropertyOptions) {
- g.emitField(w, fld, ComputedField, opt, " public ")
- if !opt.Out {
- hasArgs = true
- if !opt.Optional {
- hasRequiredArgs = true
- }
- }
- })
- if fn > 0 {
- w.Writefmtln("")
- }
-
- // Add the standard "factory" functions: get and query. These are static, so they go before the constructor.
- w.Writefmtln(" public static get(id: fabric.ID): %s {", name)
- w.Writefmtln(" return undefined; // functionality provided by the runtime")
- w.Writefmtln(" }")
- w.Writefmtln("")
- w.Writefmtln(" public static query(q: any): %s[] {", name)
- w.Writefmtln(" return undefined; // functionality provided by the runtime")
- w.Writefmtln(" }")
- w.Writefmtln("")
-
- // Next, a constructor that validates arguments and chains to the base constructor.
- var opt string
- if !hasRequiredArgs {
- opt = "?"
- }
- w.Writefmtln(" constructor(name: string, args%s: %sArgs) {", opt, name)
-
- // First, validate that required parameters exist, and store all arguments on the object.
- argLinePrefix := " "
- needsArgsCheck := hasArgs && !hasRequiredArgs
- if needsArgsCheck {
- w.Writefmtln(" if (args !== undefined) {")
- argLinePrefix += " "
- }
- forEachField(res, func(fld *types.Var, opt PropertyOptions) {
- if !opt.Out && !opt.Optional {
- w.Writefmtln("%sif (args.%s === undefined) {", argLinePrefix, opt.Name)
- w.Writefmtln("%s throw new Error(\"Missing required property '%s'\");", argLinePrefix, opt.Name)
- w.Writefmtln("%s}", argLinePrefix)
- }
- })
- if needsArgsCheck {
- w.Writefmtln(" }")
- }
-
- // Now invoke the base.
- w.Writefmtln(" super(\"%s\", name, {", res.Tok())
- forEachField(res, func(fld *types.Var, opt PropertyOptions) {
- w.Writefmt(" \"%s\": ", opt.Name)
- if opt.Out {
- w.Writefmtln("undefined,")
- } else {
- w.Writefmtln("args.%s,", opt.Name)
- }
- })
-
- w.Writefmtln(" });")
- w.Writefmtln(" }")
- w.Writefmtln("}")
-}
-
-func (g *PackGenerator) EmitStruct(w *tools.GenWriter, s *Struct) {
- g.emitStructType(w, s, s.Name())
-}
-
-func (g *PackGenerator) emitStructType(w *tools.GenWriter, t TypeMember, name tokens.Name) {
- w.Writefmtln(fmt.Sprintf("export interface %s {", name))
- forEachField(t, func(fld *types.Var, opt PropertyOptions) {
- if opt.Out {
- return // skip output properties, since those exist solely on the resource class.
- }
- g.emitField(w, fld, MaybeComputedField, opt, " ")
- })
- w.Writefmtln("}")
-}
-
-type FieldKind int
-
-const (
- NormalField FieldKind = iota
- ComputedField
- MaybeComputedField
-)
-
-func (g *PackGenerator) emitField(w *tools.GenWriter, fld *types.Var,
- kind FieldKind, opt PropertyOptions, prefix string) {
- var mods string
- if opt.Replaces {
- mods += "readonly "
- }
- if opt.Out {
- mods += "/*out*/ "
- }
- var optional string
- if opt.Optional {
- optional = "?"
- }
- typ := g.GenTypeName(fld.Type(), kind)
- if kind == ComputedField {
- typ = fmt.Sprintf("fabric.Computed<%v>", typ)
- }
- w.Writefmtln("%v%v%v%v: %v;", prefix, mods, opt.Name, optional, typ)
-}
-
-func (g *PackGenerator) GenTypeName(t types.Type, kind FieldKind) string {
- var ret string
- var skipwrap bool
- switch u := t.(type) {
- case *types.Basic:
- switch k := u.Kind(); k {
- case types.Bool:
- ret = "boolean"
- case types.String:
- ret = "string"
- case types.Float64:
- ret = "number"
- default:
- contract.Failf("Unrecognized GenTypeName basic type: %v", k)
- }
- case *types.Interface:
- ret = "any"
- case *types.Named:
- obj := u.Obj()
- if spec, kind := IsSpecial(obj); spec {
- switch kind {
- case SpecialArchiveType:
- ret = "fabric.asset.Archive"
- case SpecialAssetType:
- ret = "fabric.asset.Asset"
- case SpecialResourceType:
- ret = "fabric.Resource"
- default:
- contract.Failf("Unrecognized special type: %v", kind)
- }
- } else {
- // Our import logic will have arranged for the type name to be available.
- // IDEA: consider auto-generated import names to avoid conflicts between imported and local names.
- g.trackNameReference(obj)
- ret = obj.Name()
- }
- case *types.Map:
- ret = fmt.Sprintf("{[key: %s]: %s}", g.GenTypeName(u.Key(), kind), g.GenTypeName(u.Elem(), kind))
- case *types.Pointer:
- ret = g.GenTypeName(u.Elem(), kind) // no pointers in TypeScript, just emit the underlying type.
- skipwrap = true // don't doubly emit wrapper types
- case *types.Slice:
- ret = fmt.Sprintf("%s[]", g.GenTypeName(u.Elem(), kind)) // postfix syntax for arrays.
- default:
- contract.Failf("Unrecognized GenTypeName type: %s", reflect.TypeOf(u))
- }
-
- if !skipwrap && kind == MaybeComputedField {
- ret = fmt.Sprintf("fabric.MaybeComputed<%s>", ret)
- }
-
- return ret
-}
-
-// trackNameReference registers that we have seen a foreign package and requests that the imports be emitted for it.
-func (g *PackGenerator) trackNameReference(obj *types.TypeName) {
- // If a reference to a type within the same package and file, there is no need to register anything.
- pkg := obj.Pkg()
- member := tokens.Name(obj.Name())
- if pkg == g.CurrPkg.Pkginfo.Pkg &&
- g.CurrPkg.MemberFiles[member].Path == g.CurrFile {
- return
- }
-
- // Otherwise, we need to track the member so that we can import it later on. Make sure not to add duplicates
- // because we want to ensure we don't import the same thing twice.
- path := pkg.Path()
- members, has := g.FileImports[path]
- if !has {
- members = make(MemberImports)
- g.FileImports[path] = members
- }
- members[member] = g.Filename(obj)
-}
diff --git a/pkg/tools/lumidl/gen_rpc.go b/pkg/tools/lumidl/gen_rpc.go
deleted file mode 100644
index 6ecd2db12..000000000
--- a/pkg/tools/lumidl/gen_rpc.go
+++ /dev/null
@@ -1,547 +0,0 @@
-// Copyright 2016-2017, Pulumi Corporation. All rights reserved.
-
-package lumidl
-
-import (
- "fmt"
- "go/types"
- "path/filepath"
- "reflect"
- "sort"
- "strings"
-
- "github.com/pulumi/pulumi/pkg/tokens"
- "github.com/pulumi/pulumi/pkg/tools"
- "github.com/pulumi/pulumi/pkg/util/contract"
-)
-
-type RPCGenerator struct {
- IDLRoot string // the root where IDL is loaded from.
- IDLPkgBase string // the IDL's base package path.
- RPCPkgBase string // the RPC's base package path.
- Out string // where RPC stub outputs will be saved.
- CurrPkg *Package // the package currently being visited.
- CurrFile string // the file currently being visited.
- FileHadRes bool // true if the file had at least one resource.
- FileImports map[string]string // a map of foreign packages used in a file.
-}
-
-func NewRPCGenerator(root, idlPkgBase, rpcPkgBase, out string) *RPCGenerator {
- return &RPCGenerator{
- IDLRoot: root,
- IDLPkgBase: idlPkgBase,
- RPCPkgBase: rpcPkgBase,
- Out: out,
- }
-}
-
-func (g *RPCGenerator) Generate(pkg *Package) error {
- // Ensure the directory structure exists in the target.
- if err := mirrorDirLayout(pkg, g.Out); err != nil {
- return err
- }
-
- // Install context about the current entity being visited.
- oldpkg, oldfile := g.CurrPkg, g.CurrFile
- g.CurrPkg = pkg
- defer (func() {
- g.CurrPkg = oldpkg
- g.CurrFile = oldfile
- })()
-
- // Now walk through the package, file by file, and generate the contents.
- for relpath, file := range pkg.Files {
- g.CurrFile = relpath
- var members []Member
- for _, nm := range file.MemberNames {
- members = append(members, file.Members[nm])
- }
- path := filepath.Join(g.Out, relpath)
- if err := g.EmitFile(path, pkg, members); err != nil {
- return err
- }
- }
-
- return nil
-}
-
-func (g *RPCGenerator) EmitFile(file string, pkg *Package, members []Member) error {
- oldHadRes, oldImports := g.FileHadRes, g.FileImports
- g.FileHadRes, g.FileImports = false, make(map[string]string)
- defer (func() {
- g.FileHadRes = oldHadRes
- g.FileImports = oldImports
- })()
-
- // First, generate the body. This is required first so we know which imports to emit.
- body := g.genFileBody(file, pkg, members)
-
- // Open up a writer that overwrites whatever file contents already exist.
- w, err := tools.NewGenWriter(lumidl, file)
- if err != nil {
- return err
- }
- defer contract.IgnoreClose(w)
-
- // Emit a header into the file.
- w.EmitHeaderWarning()
-
- // Now emit the package name at the top-level.
- w.Writefmtln("package %v", pkg.Pkginfo.Pkg.Name())
- w.Writefmtln("")
-
- // And all of the imports that we're going to need.
- if g.FileHadRes || len(g.FileImports) > 0 {
- w.Writefmtln("import (")
-
- if g.FileHadRes {
- w.Writefmtln(` pbempty "github.com/golang/protobuf/ptypes/empty"`)
- w.Writefmtln(` pbstruct "github.com/golang/protobuf/ptypes/struct"`)
- w.Writefmtln(` "golang.org/x/net/context"`)
- w.Writefmtln("")
- w.Writefmtln(` "github.com/pulumi/pulumi/pkg/resource"`)
- w.Writefmtln(` "github.com/pulumi/pulumi/pkg/resource/plugin"`)
- w.Writefmtln(` "github.com/pulumi/pulumi/pkg/tokens"`)
- w.Writefmtln(` "github.com/pulumi/pulumi/pkg/util/contract"`)
- w.Writefmtln(` "github.com/pulumi/pulumi/pkg/util/mapper"`)
- w.Writefmtln(` lumirpc "github.com/pulumi/pulumi/sdk/proto/go"`)
- }
-
- if len(g.FileImports) > 0 {
- if g.FileHadRes {
- w.Writefmtln("")
- }
- // Sort the imports so they are in a correct, deterministic order.
- var imports []string
- for imp := range g.FileImports {
- imports = append(imports, imp)
- }
- sort.Strings(imports)
-
- // Now just emit a list of imports with their given names.
- for _, imp := range imports {
- name := g.FileImports[imp]
-
- // If the import referenced one of the IDL packages, we must rewrite it to an RPC package.
- contract.Assertf(strings.HasPrefix(imp, g.IDLPkgBase),
- "Inter-IDL package references not yet supported (%v is not part of %v)", imp, g.IDLPkgBase)
- var imppath string
- if imp == g.IDLPkgBase {
- imppath = g.RPCPkgBase
- } else {
- relimp := imp[len(g.IDLPkgBase)+1:]
- imppath = g.RPCPkgBase + "/" + relimp
- }
-
- w.Writefmtln(` %v "%v"`, name, imppath)
- }
- }
-
- w.Writefmtln(")")
- w.Writefmtln("")
- }
-
- // Now finally emit the actual body and close out the file.
- w.Writefmtln("%v", body)
- return w.Flush()
-}
-
-func (g *RPCGenerator) genFileBody(file string, pkg *Package, members []Member) string {
- w, err := tools.NewGenWriter(lumidl, "")
- contract.IgnoreError(err)
-
- // First, for each RPC struct/resource member, emit its appropriate generated code.
- var typedefs []Typedef
- var consts []*Const
- module := g.getFileModule(file)
- for _, m := range members {
- switch t := m.(type) {
- case *Alias:
- typedefs = append(typedefs, t)
- case *Const:
- consts = append(consts, t)
- case *Enum:
- typedefs = append(typedefs, t)
- case *Resource:
- g.EmitResource(w, module, pkg, t)
- g.EmitStructType(w, module, pkg, t)
- case *Struct:
- g.EmitStructType(w, module, pkg, t)
- default:
- contract.Failf("Unrecognized package member type: %v", reflect.TypeOf(t))
- }
- }
-
- // Next emit all supporting types. First, aliases and enum types.
- if len(typedefs) > 0 {
- g.EmitTypedefs(w, typedefs)
- }
-
- // Finally, emit any consts at the very end.
- if len(consts) > 0 {
- g.EmitConstants(w, consts)
- }
-
- err = w.Flush()
- contract.IgnoreError(err)
- return w.Buffer()
-}
-
-// getFileModule generates a module name from a filename. To do so, we simply find the path part after the root and
-// remove any file extensions, to get the underlying package's module token.
-func (g *RPCGenerator) getFileModule(file string) tokens.Module {
- module, _ := filepath.Rel(g.Out, file)
- if ext := filepath.Ext(module); ext != "" {
- extix := strings.LastIndex(module, ext)
- module = module[:extix]
- }
- return tokens.Module(module)
-}
-
-func (g *RPCGenerator) EmitResource(w *tools.GenWriter, module tokens.Module, pkg *Package, res *Resource) {
- name := res.Name()
- w.Writefmtln("/* RPC stubs for %v resource provider */", name)
- w.Writefmtln("")
-
- // Remember when we encounter resources so we can import the right packages.
- g.FileHadRes = true
-
- propopts := res.PropertyOptions()
- var hasinputs bool
- for _, propopt := range propopts {
- if !propopt.Out {
- hasinputs = true
- break
- }
- }
-
- // Emit a type token.
- token := fmt.Sprintf("%v:%v:%v", pkg.Name, module, name)
- w.Writefmtln("// %[1]vToken is the type token corresponding to the %[1]v package type.", name)
- w.Writefmtln(`const %vToken = tokens.Type("%v")`, name, token)
- w.Writefmtln("")
-
- // Now, generate an ops interface that the real provider will implement.
- w.Writefmtln("// %[1]vProviderOps is a pluggable interface for %[1]v-related management functionality.", name)
- w.Writefmtln("type %vProviderOps interface {", name)
- w.Writefmtln(" Configure(ctx context.Context, vars map[tokens.ModuleMember]string) error")
- w.Writefmtln(" Check(ctx context.Context, obj *%v, property string) error", name)
- w.Writefmtln(" Diff(ctx context.Context, id resource.ID,")
- w.Writefmtln(" old *%[1]v, new *%[1]v, diff *resource.ObjectDiff) ([]string, error)", name)
- w.Writefmtln(" Create(ctx context.Context, obj *%v) (resource.ID, error)", name)
- w.Writefmtln(" Update(ctx context.Context, id resource.ID,")
- w.Writefmtln(" old *%[1]v, new *%[1]v, diff *resource.ObjectDiff) error", name)
- w.Writefmtln(" Delete(ctx context.Context, id resource.ID, obj %v) error", name)
- w.Writefmtln("}")
- w.Writefmtln("")
-
- // Next generate all the RPC scaffolding goo
- w.Writefmtln("// %[1]vProvider is a dynamic gRPC-based plugin for managing %[1]v resources.", name)
- w.Writefmtln("type %vProvider struct {", name)
- w.Writefmtln(" ops %vProviderOps", name)
- w.Writefmtln("}")
- w.Writefmtln("")
- w.Writefmtln("// New%vProvider allocates a resource provider that delegates to a ops instance.", name)
- w.Writefmtln("func New%[1]vProvider(ops %[1]vProviderOps) lumirpc.ResourceProviderServer {", name)
- w.Writefmtln(" contract.Assert(ops != nil)")
- w.Writefmtln(" return &%vProvider{ops: ops}", name)
- w.Writefmtln("}")
- w.Writefmtln("")
- w.Writefmtln("func (p *%vProvider) Configure(", name)
- w.Writefmtln(" ctx context.Context, req *lumirpc.ConfigureRequest) (*pbempty.Empty, error) {")
- w.Writefmtln(" vars := make(map[tokens.ModuleMember]string)")
- w.Writefmtln(" for k, v := range req.GetVariables() {")
- w.Writefmtln(" vars[tokens.ModuleMember(k)] = v")
- w.Writefmtln(" }")
- w.Writefmtln(" if err := p.ops.Configure(ctx, vars); err != nil {")
- w.Writefmtln(" return nil, err")
- w.Writefmtln(" }")
- w.Writefmtln(" return &pbempty.Empty{}, nil")
- w.Writefmtln("}")
- w.Writefmtln("")
- w.Writefmtln("func (p *%vProvider) Check(", name)
- w.Writefmtln(" ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {")
- w.Writefmtln(" contract.Assert(resource.URN(req.GetUrn()).Type() == %vToken)", name)
- w.Writefmtln(" obj, _, err := p.Unmarshal(req.GetProperties(), true)")
- w.Writefmtln(" if obj == nil || err != nil {")
- w.Writefmtln(" return plugin.NewCheckResponse(err), nil")
- w.Writefmtln(" }")
- w.Writefmtln(" var failures []error")
- // check global properties:
- w.Writefmtln(" if failure := p.ops.Check(ctx, obj, \"\"); failure != nil {")
- w.Writefmtln(" failures = append(failures, failure)")
- w.Writefmtln(" }")
- // check each input property:
- if hasinputs {
- for _, opts := range propopts {
- if !opts.Out {
- w.Writefmtln(" if failure := p.ops.Check(ctx, obj, \"%v\"); failure != nil {", opts.Name)
- w.Writefmtln(" failures = append(failures,")
- w.Writefmtln(" resource.NewPropertyError(\"%v\", \"%v\", failure))", name, opts.Name)
- w.Writefmtln(" }")
- }
- }
- w.Writefmtln(" if len(failures) > 0 {")
- w.Writefmtln(" return plugin.NewCheckResponse(resource.NewErrors(failures)), nil")
- w.Writefmtln(" }")
- }
- w.Writefmtln(" return plugin.NewCheckResponse(nil), nil")
- w.Writefmtln("}")
- w.Writefmtln("")
- w.Writefmtln("func (p *%vProvider) Create(", name)
- w.Writefmtln(" ctx context.Context, req *lumirpc.CreateRequest) (*lumirpc.CreateResponse, error) {")
- w.Writefmtln(" contract.Assert(resource.URN(req.GetUrn()).Type() == %vToken)", name)
- w.Writefmtln(" obj, _, err := p.Unmarshal(req.GetProperties(), false)")
- w.Writefmtln(" if err != nil {")
- w.Writefmtln(" return nil, err")
- w.Writefmtln(" }")
- w.Writefmtln(" id, err := p.ops.Create(ctx, obj)")
- w.Writefmtln(" if err != nil {")
- w.Writefmtln(" return nil, err")
- w.Writefmtln(" }")
- w.Writefmtln(" props, err := plugin.MarshalProperties(")
- w.Writefmtln(" resource.NewPropertyMap(obj), plugin.MarshalOptions{})")
- w.Writefmtln(" if err != nil {")
- w.Writefmtln(" return nil, err")
- w.Writefmtln(" }")
- w.Writefmtln(" return &lumirpc.CreateResponse{Id: string(id), Properties: props}, nil")
- w.Writefmtln("}")
- w.Writefmtln("")
- w.Writefmtln("func (p *%vProvider) Diff(", name)
- w.Writefmtln(" ctx context.Context, req *lumirpc.DiffRequest) (*lumirpc.DiffResponse, error) {")
- w.Writefmtln(" contract.Assert(resource.URN(req.GetUrn()).Type() == %vToken)", name)
- w.Writefmtln(" id := resource.ID(req.GetId())")
- w.Writefmtln(" old, oldprops, err := p.Unmarshal(req.GetOlds(), false)")
- w.Writefmtln(" if err != nil {")
- w.Writefmtln(" return nil, err")
- w.Writefmtln(" }")
- w.Writefmtln(" new, newprops, err := p.Unmarshal(req.GetNews(), true)")
- w.Writefmtln(" if new == nil || err != nil {")
- w.Writefmtln(" return nil, err")
- w.Writefmtln(" }")
- w.Writefmtln(" var replaces []string")
- w.Writefmtln(" diff := oldprops.Diff(newprops)")
- w.Writefmtln(" if diff != nil {")
- for _, opts := range propopts {
- if opts.Replaces {
- w.Writefmtln(" if diff.Changed(\"%v\") {", opts.Name)
- w.Writefmtln(" replaces = append(replaces, \"%v\")", opts.Name)
- w.Writefmtln(" }")
- }
- }
- w.Writefmtln(" }")
- w.Writefmtln(" more, err := p.ops.Diff(ctx, id, old, new, diff)")
- w.Writefmtln(" if err != nil {")
- w.Writefmtln(" return nil, err")
- w.Writefmtln(" }")
- w.Writefmtln(" return &lumirpc.DiffResponse{")
- w.Writefmtln(" Replaces: append(replaces, more...),")
- w.Writefmtln(" }, err")
- w.Writefmtln("}")
- w.Writefmtln("")
- w.Writefmtln("func (p *%vProvider) Update(", name)
- w.Writefmtln(" ctx context.Context, req *lumirpc.UpdateRequest) (*lumirpc.UpdateResponse, error) {")
- w.Writefmtln(" contract.Assert(resource.URN(req.GetUrn()).Type() == %vToken)", name)
- w.Writefmtln(" id := resource.ID(req.GetId())")
- w.Writefmtln(" old, oldprops, err := p.Unmarshal(req.GetOlds(), false)")
- w.Writefmtln(" if err != nil {")
- w.Writefmtln(" return nil, err")
- w.Writefmtln(" }")
- w.Writefmtln(" new, newprops, err := p.Unmarshal(req.GetNews(), false)")
- w.Writefmtln(" if err != nil {")
- w.Writefmtln(" return nil, err")
- w.Writefmtln(" }")
- w.Writefmtln(" diff := oldprops.Diff(newprops)")
- w.Writefmtln(" if err := p.ops.Update(ctx, id, old, new, diff); err != nil {")
- w.Writefmtln(" return nil, err")
- w.Writefmtln(" }")
- w.Writefmtln(" props, err := plugin.MarshalProperties(")
- w.Writefmtln(" resource.NewPropertyMap(new), plugin.MarshalOptions{})")
- w.Writefmtln(" if err != nil {")
- w.Writefmtln(" return nil, err")
- w.Writefmtln(" }")
- w.Writefmtln(" return &lumirpc.UpdateResponse{Properties: props}, nil")
- w.Writefmtln("}")
- w.Writefmtln("")
- w.Writefmtln("func (p *%vProvider) Delete(", name)
- w.Writefmtln(" ctx context.Context, req *lumirpc.DeleteRequest) (*pbempty.Empty, error) {")
- w.Writefmtln(" contract.Assert(resource.URN(req.GetUrn()).Type() == %vToken)", name)
- w.Writefmtln(" id := resource.ID(req.GetId())")
- w.Writefmtln(" obj, _, err := p.Unmarshal(req.GetProperties(), false)")
- w.Writefmtln(" if err != nil {")
- w.Writefmtln(" return nil, err")
- w.Writefmtln(" }")
- w.Writefmtln(" if err := p.ops.Delete(ctx, id, *obj); err != nil {")
- w.Writefmtln(" return nil, err")
- w.Writefmtln(" }")
- w.Writefmtln(" return &pbempty.Empty{}, nil")
- w.Writefmtln("}")
- w.Writefmtln("")
- w.Writefmtln("func (p *%vProvider) Unmarshal(", name)
- w.Writefmtln(" v *pbstruct.Struct, allowUnknowns bool) (*%v, resource.PropertyMap, error) {", name)
- w.Writefmtln(" opts := plugin.MarshalOptions{AllowUnknowns: allowUnknowns}")
- w.Writefmtln(" props, err := plugin.UnmarshalProperties(v, opts)")
- w.Writefmtln(" if err != nil {")
- w.Writefmtln(" return nil, nil, err")
- w.Writefmtln(" }")
- w.Writefmtln(" if allowUnknowns && props.ContainsUnknowns() {")
- w.Writefmtln(" return nil, props, nil")
- w.Writefmtln(" }")
- w.Writefmtln(" var obj %v", name)
- w.Writefmtln(" return &obj, props, mapper.MapIU(props.Mappable(), &obj)")
- w.Writefmtln("}")
- w.Writefmtln("")
-}
-
-func (g *RPCGenerator) EmitStructType(w *tools.GenWriter, module tokens.Module, pkg *Package, t TypeMember) {
- name := t.Name()
- w.Writefmtln("/* Marshalable %v structure(s) */", name)
- w.Writefmtln("")
-
- props := t.Properties()
- propopts := t.PropertyOptions()
- w.Writefmtln("// %v is a marshalable representation of its corresponding IDL type.", name)
- w.Writefmtln("type %v struct {", name)
- for i, prop := range props {
- opts := propopts[i]
- // Make a JSON tag for this so we can serialize; note that outputs are always optional in this position.
- jsontag := makeLumiTag(opts)
- w.Writefmtln(" %v %v %v",
- prop.Name(), g.GenTypeName(prop.Type(), opts.Optional || opts.In || opts.Out), jsontag)
- }
- w.Writefmtln("}")
- w.Writefmtln("")
-
- if len(props) > 0 {
- w.Writefmtln("// %v's properties have constants to make dealing with diffs and property bags easier.", name)
- w.Writefmtln("const (")
- for i, prop := range props {
- opts := propopts[i]
- w.Writefmtln(" %v_%v = \"%v\"", name, prop.Name(), opts.Name)
- }
- w.Writefmtln(")")
- w.Writefmtln("")
- }
-}
-
-// makeLumiTag turns a set of property options into a serializable JSON tag.
-func makeLumiTag(opts PropertyOptions) string {
- var flags string
- if opts.Optional || opts.In || opts.Out {
- flags = ",optional"
- }
- return fmt.Sprintf("`pulumi:\"%v%v\"`", opts.Name, flags)
-}
-
-func (g *RPCGenerator) GenTypeName(t types.Type, opt bool) string {
- switch u := t.(type) {
- case *types.Basic:
- switch k := u.Kind(); k {
- case types.Bool:
- return "bool"
- case types.String:
- return "string"
- case types.Float64:
- return "float64"
- default:
- contract.Failf("Unrecognized GenTypeName basic type: %v", k)
- }
- case *types.Interface:
- return "interface{}"
- case *types.Named:
- obj := u.Obj()
- // For resource types, simply emit an ID, since that is what will have been serialized.
- if IsResource(obj, u) {
- return "resource.ID"
- }
-
- // For references to the special predefined types, use the runtime provider representation.
- if spec, kind := IsSpecial(obj); spec {
- switch kind {
- case SpecialArchiveType:
- return "resource.Archive"
- case SpecialAssetType:
- return "resource.Asset"
- default:
- contract.Failf("Unexpected special kind: %v", kind)
- }
- }
-
- // Otherwise, see how to reference the type, based on imports.
- pkg := obj.Pkg()
- name := obj.Name()
-
- // If this came from the same package, Go can access it without qualification.
- if pkg == g.CurrPkg.Pkginfo.Pkg {
- return name
- }
-
- // Otherwise, we will need to refer to a qualified import name.
- impname := g.registerImport(pkg)
- return fmt.Sprintf("%v.%v", impname, name)
- case *types.Map:
- return fmt.Sprintf("map[%v]%v", g.GenTypeName(u.Key(), false), g.GenTypeName(u.Elem(), false))
- case *types.Pointer:
- // If this isn't an optional property, and the underlying type is a resource or special type, unpointerize it.
- elem := u.Elem()
- unptr := false
- if !opt {
- if elnm, iselnm := elem.(*types.Named); iselnm {
- if IsResource(elnm.Obj(), elnm) {
- unptr = true
- } else if spec, _ := IsSpecial(elnm.Obj()); spec {
- unptr = true
- }
- }
- }
- if unptr {
- return g.GenTypeName(elem, false)
- }
- return fmt.Sprintf("*%v", g.GenTypeName(u.Elem(), false))
- case *types.Slice:
- return fmt.Sprintf("[]%v", g.GenTypeName(u.Elem(), false)) // postfix syntax for arrays.
- default:
- contract.Failf("Unrecognized GenTypeName type: %v", reflect.TypeOf(u))
- }
- return ""
-}
-
-// registerImport registers that we have seen a foreign package and requests that the imports be emitted for it.
-func (g *RPCGenerator) registerImport(pkg *types.Package) string {
- path := pkg.Path()
- if impname, has := g.FileImports[path]; has {
- return impname
- }
-
- // If we haven't seen this yet, allocate an import name for it. For now, we just use the package name with two
- // leading underscores, to avoid accidental collisions with other names in the file.
- name := "__" + pkg.Name()
- g.FileImports[path] = name
- return name
-}
-
-func (g *RPCGenerator) EmitTypedefs(w *tools.GenWriter, typedefs []Typedef) {
- w.Writefmtln("/* Typedefs */")
- w.Writefmtln("")
-
- w.Writefmtln("type (")
- for _, td := range typedefs {
- w.Writefmtln(" %v %v", td.Name(), td.Target())
- }
- w.Writefmtln(")")
-
- w.Writefmtln("")
-}
-
-func (g *RPCGenerator) EmitConstants(w *tools.GenWriter, consts []*Const) {
- w.Writefmtln("/* Constants */")
- w.Writefmtln("")
-
- w.Writefmtln("const (")
- for _, konst := range consts {
- w.Writefmtln(" %v %v = %v", konst.Name(), g.GenTypeName(konst.Type, false), konst.Value)
- }
- w.Writefmtln(")")
-
- w.Writefmtln("")
-}
diff --git a/pkg/tools/lumidl/options.go b/pkg/tools/lumidl/options.go
deleted file mode 100644
index 8a07047f8..000000000
--- a/pkg/tools/lumidl/options.go
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2016-2017, Pulumi Corporation. All rights reserved.
-
-package lumidl
-
-import (
- "reflect"
- "strings"
-
- "github.com/pulumi/pulumi/pkg/diag"
- "github.com/pulumi/pulumi/pkg/util/cmdutil"
-)
-
-// PropertyOptionsTag is the field tag the IDL compiler uses to find property options.
-const PropertyOptionsTag = "pulumi"
-
-// PropertyOptions represents a parsed field tag, controlling how properties are treated.
-type PropertyOptions struct {
- Name string // the property name to emit into the package.
- Optional bool // true if this is an optional property.
- Replaces bool // true if changing this property triggers a replacement of this resource.
- In bool // true if this is part of the resource's input, but not its output, properties.
- Out bool // true if the property is part of the resource's output, rather than input, properties.
-}
-
-// ParsePropertyOptions parses a tag into a structured set of options.
-func ParsePropertyOptions(tag string) PropertyOptions {
- opts := PropertyOptions{}
- if lumi, has := reflect.StructTag(tag).Lookup(PropertyOptionsTag); has {
- // The first element is the name; all others are optional flags. All are delimited by commas.
- if keys := strings.Split(lumi, ","); len(keys) > 0 {
- opts.Name = keys[0]
- for _, key := range keys[1:] {
- switch key {
- case "optional":
- opts.Optional = true
- case "replaces":
- opts.Replaces = true
- case "in":
- opts.In = true
- case "out":
- opts.Out = true
- default:
- cmdutil.Diag().Errorf(diag.Message("unrecognized tag `pulumi:\"%v\"`"), key)
- }
- }
- }
- }
- return opts
-}
diff --git a/pkg/tools/lumidl/package.go b/pkg/tools/lumidl/package.go
deleted file mode 100644
index c5fa6f4cc..000000000
--- a/pkg/tools/lumidl/package.go
+++ /dev/null
@@ -1,130 +0,0 @@
-// Copyright 2016-2017, Pulumi Corporation. All rights reserved.
-
-package lumidl
-
-import (
- "go/ast"
- "go/constant"
- "go/token"
- "go/types"
-
- "golang.org/x/tools/go/loader"
-
- "github.com/pulumi/pulumi/pkg/tokens"
- "github.com/pulumi/pulumi/pkg/util/contract"
-)
-
-type Package struct {
- Name tokens.PackageName // the package name.
- Program *loader.Program // the fully parsed/analyzed Go program.
- Pkginfo *loader.PackageInfo // the Go package information.
- Files map[string]*File // the files inside of this package.
- MemberFiles map[tokens.Name]*File // a map from member to the file containing it.
-}
-
-func NewPackage(name tokens.PackageName, prog *loader.Program, pkginfo *loader.PackageInfo) *Package {
- return &Package{
- Name: name,
- Program: prog,
- Pkginfo: pkginfo,
- Files: make(map[string]*File),
- MemberFiles: make(map[tokens.Name]*File),
- }
-}
-
-func (pkg *Package) AddMember(file *File, nm tokens.Name, m Member) {
- _, has := file.Members[nm]
- contract.Assertf(!has, "Unexpected duplicate member %v", nm)
- file.Members[nm] = m
- file.MemberNames = append(file.MemberNames, nm)
- pkg.MemberFiles[nm] = file
-}
-
-type File struct {
- Path string // a relative path to the file.
- Module tokens.Module // the module token for this file.
- Node *ast.File // the Go file object.
- Members map[tokens.Name]Member // a map of all members, membered and internal.
- MemberNames []tokens.Name // the list of member keys in the order in which they were encountered.
-}
-
-func NewFile(path string, mod tokens.Module, node *ast.File) *File {
- return &File{
- Path: path,
- Module: mod,
- Node: node,
- Members: make(map[tokens.Name]Member),
- }
-}
-
-type Member interface {
- Tok() tokens.ModuleMember // the member's token.
- Name() tokens.Name // the name of the member.
- Exported() bool // true if this member is membered.
- Pos() token.Pos // the file defining this member.
-}
-
-type member struct {
- tok tokens.ModuleMember
- exported bool
- pos token.Pos
-}
-
-func (m *member) Tok() tokens.ModuleMember { return m.tok }
-func (m *member) Name() tokens.Name { return tokens.Name(m.tok.Name()) }
-func (m *member) Exported() bool { return m.exported }
-func (m *member) Pos() token.Pos { return m.pos }
-
-type TypeMember interface {
- Member
- Struct() *types.Struct // the raw underlying struct.
- Properties() []*types.Var // a flattened list of all properties (including embedded ones).
- PropertyOptions() []PropertyOptions // a flattened list of all property options.
-}
-
-type Resource struct {
- member
- s *types.Struct // the underlying Go struct node.
- props []*types.Var
- popts []PropertyOptions
-}
-
-func (r *Resource) Struct() *types.Struct { return r.s }
-func (r *Resource) Properties() []*types.Var { return r.props }
-func (r *Resource) PropertyOptions() []PropertyOptions { return r.popts }
-
-type Struct struct {
- member
- s *types.Struct
- props []*types.Var
- popts []PropertyOptions
-}
-
-func (r *Struct) Struct() *types.Struct { return r.s }
-func (r *Struct) Properties() []*types.Var { return r.props }
-func (r *Struct) PropertyOptions() []PropertyOptions { return r.popts }
-
-type Typedef interface {
- Member
- Target() types.Type
-}
-
-type Alias struct {
- member
- target types.Type
-}
-
-func (a *Alias) Target() types.Type { return a.target }
-
-type Enum struct {
- member
- Values []string
-}
-
-func (a *Enum) Target() types.Type { return types.Typ[types.String] }
-
-type Const struct {
- member
- Type types.Type
- Value constant.Value
-}
diff --git a/pkg/tools/lumidl/paths.go b/pkg/tools/lumidl/paths.go
deleted file mode 100644
index cd0ff99f9..000000000
--- a/pkg/tools/lumidl/paths.go
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2016-2017, Pulumi Corporation. All rights reserved.
-
-package lumidl
-
-import (
- "path/filepath"
-
- "golang.org/x/tools/go/loader"
-
- "github.com/pulumi/pulumi/pkg/util/contract"
-)
-
-// RelFilename gets the target filename for any given position relative to the root.
-func RelFilename(root string, prog *loader.Program, p goPos) string {
- pos := p.Pos()
- source := prog.Fset.Position(pos).Filename // the source filename.`
- rel, err := filepath.Rel(root, source) // make it relative to the root.
- contract.AssertNoError(err)
- return rel
-}
diff --git a/pkg/tools/lumidl/types.go b/pkg/tools/lumidl/types.go
deleted file mode 100644
index c3557ae1e..000000000
--- a/pkg/tools/lumidl/types.go
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright 2016-2017, Pulumi Corporation. All rights reserved.
-
-package lumidl
-
-import (
- "go/types"
- "reflect"
- "strings"
-
- "github.com/pulumi/pulumi/pkg/resource/idl"
- "github.com/pulumi/pulumi/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 IsResource(obj, t) {
- return true
- }
- spec, _ := IsSpecial(obj)
- return spec
-}
-
-// IsResource returns true if a type is a special IDL resource.
-func IsResource(obj *types.TypeName, t types.Type) bool {
- contract.Assert(obj != nil)
-
- // If this is a resource type itself, then we're done.
- if IsSpecialResource(obj) {
- return true
- }
-
- // 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 IsSpecialResource(named.Obj()) {
- return true
- }
- }
- }
- }
- }
- return false
-}
-
-type SpecialType int
-
-const (
- NotSpecialType = iota
- SpecialResourceType
- SpecialAssetType
- SpecialArchiveType
-)
-
-var (
- idlArchiveType = reflect.TypeOf(idl.Archive{})
- idlAssetType = reflect.TypeOf(idl.Asset{})
- idlResourceType = reflect.TypeOf(idl.Resource{})
-)
-
-// pkgMatch compares two packages. If the first is a vendored version of match, it still returns true.
-func pkgMatch(pkg string, match string) bool {
- ix := strings.LastIndex(pkg, match)
- return ix != -1 && ix+len(match) == len(pkg)
-}
-
-func IsSpecial(obj *types.TypeName) (bool, SpecialType) {
- if obj != nil && pkgMatch(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
- }
- }
- return false, NotSpecialType
-}
-
-func IsSpecialResource(obj *types.TypeName) bool {
- spec, kind := IsSpecial(obj)
- return (spec && kind == SpecialResourceType)
-}