Commit graph

14 commits

Author SHA1 Message Date
joeduffy a28f02ce68 Use intrinsics in place of predefineds
This change leverages intrinsics in place of the predefined types.
It remains to be seen if we can reach 100% on this, however I am hopeful.
It's also nice that the system will be built "out of itself" with this
approach; in other words, each of the types is simply a Mufile that can
use conditional targeting as appropriate for the given cloud providers.
If we find that this isn't enough, we can always bring back the concept.
2016-12-05 16:13:49 -08:00
joeduffy 5b791aab77 Introduce intrinsic types
This change eliminates the special type mu/extension in favor of extensible
intrinsic types.  This subsumes the previous functionality while also fixing
a number of warts with the old model.

In particular, the old mu/extension approach deferred property binding until
very late in the compiler.  In fact, too late.  The backend provider for an
extension simply received an untyped bag of stuff, which it then had to
deal with.  Unfortunately, some operations in the binder are inaccessible
at this point because doing so would cause a cycle.  Furthermore, some
pertinent information is gone at this point, like the scopes and symtables.

The canonical example where we need this is binding services names to the
services themselves; e.g., the AWS CloudFormation "DependsOn" property should
resolve to the actual service names, not the string values.  In the limit,
this requires full binding information.

There were a few solutions I considered, including ones that've required
less code motion, however this one feels the most elegant.

Now we permit types to be marked as "intrinsic."  Binding to these names
is done exactly as ordinary name binding, unlike the special mu/extension
provider name.  In fact, just about everything except code-generation for
these types is the same as ordinary types.  This is perfect for the use case
at hand, which is binding properties.

After this change, for example, "DependsOn" is expanded to real service
names precisely as we need.

As part of this change, I added support for three new basic schema types:

* ast.StringList ("string[]"): a list of strings.
* ast.StringMap ("map[string]any"): a map of strings to anys.
* ast.ServiceList ("service[]"): a list of service references.

Obviously we need to revisit this and add a more complete set.  This work
is already tracked by marapongo/mu#9.

At the end of the day, it's likely I will replace all hard-coded predefined
types with intrinsic types, for similar reasons to the above.
2016-12-05 13:46:18 -08:00
joeduffy 504659c38b Remember stack property values (including bounds)
We need to access the bound property values for a given stack, especially
during code-generation.  This information was present for services before,
however not for stacks constructed via other means (e.g., the top-most one).
This change adds a PropertyValues bag plus a corresponding BoundPropertyValues
to the ast.Stack type.
2016-12-05 10:13:57 -08:00
joeduffy 94cd53f2dd Fix a reference to Props that should be BoundProps 2016-12-03 15:23:28 -08:00
joeduffy e3a2002155 Support binding to arbitrary service types
This implements support for arbitrary service types on properties,
not just the weakly typed "service".  For example, in the AWS stacks,
the aws/ec2/route type requires a routeTable, among other things:

        name: aws/ec2/route
        properties:
                routeTable:
                        type: aws/ec2/routeTable

This not only binds the definition of such properties, but also the
callsites of those creating stacks and supplying values for them.
This includes checking for concrete, instantiated, and even base
types, so that, for instance, if a custom stack derived from
aws/ec2/routeTable using the base property, in the above example
it could be supplied as a legal value for the routeTable property.
2016-12-03 13:00:08 -08:00
joeduffy 4cf6be0f07 Add some property binding tests
This change adds a handful of property binding tests.

It also fixes:

* AsName should assert IsName.

* Enumerate properties stably, so that it is deterministic.

* Do not issue errors about unrecognized properties for the special
  `mu/extension` type.  It's entire purpose in life is to offer an
  entirely custom set of properties, which the provider is meant to
  validate.

* Default to an empty map if properties are missing.

* Add a "/" to the end of the namespace from the workspace, if present.

And rearranges some code:

* Rename the LiteralX types to XLiteral; e.g., StringLiteral instead of
  LiteralString.  I kept typing XLiteral erroneously.

* Eliminate the Mu prefix on all of the predefined type and service
  functions and types.  It's superfluous and reads nicer this way.

* Swap the order of "expected" vs. "got" in the error message about
  incorrect property types.  It used to say "got %v, expected %v"; I
  personally find that it is more helpful if it says "expected %v,
  got %v".  YMMV.
2016-12-02 14:33:22 -08:00
joeduffy 1302fc8a47 Add rudimentary template expansion
This change performs template expansion both for root stack documents in
addition to the transitive closure of dependencies.  There are many ongoing
design and implementation questions about how this should actually work;
please see marapongo/mu#7 for a discussion of them.
2016-11-25 12:58:29 -08:00
joeduffy e02921dc35 Finish dependency and type binding
This change completes the implementation of dependency and type binding.
The top-level change here is that, during the first semantic analysis AST walk,
we gather up all unknown dependencies.  Then the compiler resolves them, caching
the lookups to ensure that we don't load the same stack twice.  Finally, during
the second and final semantic analysis AST walk, we populate the bound nodes
by looking up what the compiler resolved for us.
2016-11-23 07:26:45 -08:00
joeduffy 5f3af891f7 Support Workspaces
This change adds support for Workspaces, a convenient way of sharing settings
among many Stacks, like default cluster targets, configuration settings, and the
like, which are not meant to be distributed as part of the Stack itself.

The following things are included in this checkin:

* At workspace initialization time, detect and parse the .mu/workspace.yaml
  file.  This is pretty rudimentary right now and contains just the default
  cluster targets.  The results are stored in a new ast.Workspace type.

* Rename "target" to "cluster".  This impacts many things, including ast.Target
  being changed to ast.Cluster, and all related fields, the command line --target
  being changed to --cluster, various internal helper functions, and so on.  This
  helps to reinforce the desired mental model.

* Eliminate the ast.Metadata type.  Instead, the metadata moves directly onto
  the Stack.  This reflects the decision to make Stacks "the thing" that is
  distributed, versioned, and is the granularity of dependency.

* During cluster targeting, add the workspace settings into the probing logic.
  We still search in the same order: CLI > Stack > Workspace.
2016-11-22 10:41:07 -08:00
joeduffy a23d151610 Fix a type assertion (should be string, not ast.Name) 2016-11-19 11:22:58 -08:00
joeduffy c2b5480d95 Fix a couple missed "parameter"s in the property rename 2016-11-19 11:18:42 -08:00
joeduffy ed0710dd0b Rename parameters to properties
The more I live with the current system, the more I prefer "properties" to
"parameters" for stacks and services.  Although it is true that these things
are essentially construction-time arguments, they manifest more like properties
in the way they are used; in fact, if you think of the world in terms of primary
constructors, the distinction is pretty subtle anyway.

For example, when creating a new service, we say the following:

        services:
                private:
                        some/service:
                                a: 0
                                b: true
                                c: foo

This looks like a, b, and c are properties of the type some/service.  If, on
the other hand, we kept calling these parameters, then you'd arguably prefer to
see the following:

        services:
                private:
                        some/service:
                                arguments:
                                        a: 0
                                        b: true
                                        c: foo

This is a more imperative than declarative view of the world, which I dislike
(especially because it is more verbose).

Time will tell whether this is the right decision or not ...
2016-11-19 10:34:51 -08:00
joeduffy 2e11d9a1e9 Add a strongly typed Service for mu/extension 2016-11-19 10:22:56 -08:00
joeduffy be4f3c6df9 Sketch out the service compilation for the AWS backend
This is another change of mostly placeholders.

In general, there will be three kinds of types handled by code-generation:

* Mu primitives will be expanded into AWS goo in a very specialized way, to
  accomplish the desired Mu semantics for those abstractions.

* AWS-specific extension types (mu/extension) will be recognized, so that we
  can create special AWS resources like S3 buckets, DynamoDB tables, etc.

* Anything else is interpreted as a reference to another stack that will be
  instantiated at deployment time (basically through template expansion).

This change does rearrange two noteworthy things in the core compiler, however:
first, it creates a place for bound nodes in the public and private service
references, so that the backend can access the raw stack types behind them; and
second, it moves the predefined types underneath their own package to avoid cycles.
2016-11-18 18:12:26 -08:00