Commit graph

3091 commits

Author SHA1 Message Date
joeduffy 60ce2d03c3 Add a true error for CloudFormation template marshaling failures 2016-11-18 17:15:00 -08:00
joeduffy 6dfc528ad1 Create a new core.Compiland type
This change rejiggers a few things so that we can more clearly introduce
a boundary between front- and back-end compiler phases, including sharing more,
like a diagnostics sink.  Future extensions will include backend code-generation
options.
2016-11-18 17:08:44 -08:00
joeduffy 0b34f256f0 Sketch out more AWS backend code-generator bits and pieces
This change includes a few steps towards AWS backend code-generation:

* Add a BoundDependencies property to ast.Stack to remember the *ast.Stack
  objects bound during Stack binding.

* Make a few CloudFormation properties optional (cfOutput Export/Condition).

* Rename clouds.ArchMap, clouds.ArchNames, schedulers.ArchMap, and
  schedulers.ArchNames to clouds.Values, clouds.Names, schedulers.Values,
  and schedulers.Names, respectively.  This reads much nicer to my eyes.

* Create a new anonymous ast.Target for deployments if no specific target
  was specified; this is to support quick-and-easy "one off" deployments,
  as will be common when doing local development.

* Sketch out more of the AWS Cloud implementation.  We actually map the
  Mu Services into CloudFormation Resources; well, kinda sorta, since we
  don't actually have Service-specific logic in here yet, however all of
  the structure and scaffolding is now here.
2016-11-18 16:46:36 -08:00
joeduffy e56a34b4e0 Make ast.StableX routines for the various AST maps
We previously used stable enumeration of the various AST maps in the core
visitor, however we now need stable enumeration in more places (like the AWS
backend I am working on).  This change refactors this logic to expose a set
of core ast.StableX routines that stably enumerate maps, and then simply uses
them in place of the existing visitor logic.  (Missing generics right now...)
2016-11-18 15:57:07 -08:00
joeduffy 66a3fc2b07 Add AWS CloudFormation payload structs
This change simply adds the necessary AWS CloudFormation struct types to
permit marshaling and unmarshaling to/from JSON and YAML.  This will be used
by the AWS cloud provider's backend code-generation.  It adds a bit of strong
typing so that we can catch more errors at compile-time (both for our own sanity
but also to provide developers better diagnostics when compiling their stacks).
2016-11-18 15:10:09 -08:00
joeduffy 2a2c93f8ab Add a Backend interface, and dispatch to it
This change adds a Backend Phase to the compiler, implemented by each of the
cloud/scheduler implementations.  It also reorganizes some of the modules to
ensure we can do everything we need without cycles, including introducing the
mu/pkg/compiler/backends package, under which the clouds/ and schedulers/
sub-packages now reside.  The backends.New(Arch) factory function acts as the
entrypoint into the entire thing so callers can easily create new Backend instances.
2016-11-18 12:40:15 -08:00
joeduffy f5d310ae50 Rename BuildJSON/BuildYAML to just BuildFile
This change is more consistent with our approach to file extensions
elsewhere in the compiler, and prevents an explosion of APIs should we
ever want to support more.
2016-11-17 15:13:36 -08:00
joeduffy 8fa1fd9082 Add some targeting tests
This adds some tests around cloud targeting, in addition to enabling builds
to use in-memory Mufiles (mostly to make testing simpler, but this is a
generally useful capability to have when hosting the compiler API).
2016-11-17 13:08:20 -08:00
joeduffy 6fb6c2de09 Add cloud target and architecture detection
This change implements most of the cloud target and architecture detection
logic, along with associated verification and a bunch of new error messages.

There are two settings for picking a cloud destination:

* Architecture: this specifies the combination of cloud (e.g., AWS, GCP, etc)
      plus scheduler (e.g., none, Swarm, ECS, etc).

* Target: a named, preconfigured entity that includes both an Architecture and
      an assortment of extra default configuration options.

The general idea here is that you can preconfigure a set of Targets for
named environments like "prod", "stage", etc.  Those can either exist in a
single Mufile, or the Mucluster file if they are shared amongst multiple
Mufiles.  This can be specified at the command line as such:

        $ mu build --target=stage

Furthermore, a given environment may be annointed the default, so that

        $ mu build

selects that environment without needing to say so explicitly.

It is also possible to specify an architecture at the command line for
scenarios where you aren't intending to target an existing named environment.
This is good for "anonymous" testing scenarios or even just running locally:

        $ mu build --arch=aws
        $ mu build --arch=aws:ecs
        $ mu build --arch=local:kubernetes
        $ .. and so on ..

This change does little more than plumb these settings around, verify them,
etc., however it sets us up to actually start dispating to the right backend.
2016-11-17 10:30:37 -08:00
joeduffy f1627fed2b Create a new mu/pkg/compiler/core package
This change creates a new mu/pkg/compiler/core package for any fundamental
compiler types that need to be shared among the various compiler packages
(.../compiler, .../compiler/clouds/..., and .../compiler/schedulers/...).
This avoids package cycles.
2016-11-17 08:52:54 -08:00
joeduffy 8a7fbf019c Add the ability to select a cloud provider
This adds two packages:

        mu/pkg/compiler/clouds
        mu/pkg/compiler/schedulers

And introduces enums for the cloud targets we expect to support.

It also adds the ability at the command line to specify a provider;
for example:

        $ mu build --target=aws         # AWS native
        $ mu build --target=aws:ecs     # AWS ECS
        $ mu build -t=gcp:kubernetes    # Kube on GCP
2016-11-17 07:00:52 -08:00
joeduffy 54148c67e4 Bind predefined stack types
This prepopulates the symbol table with our predefined "primitive" types
like mu/container, mu/gateway, mu/func, and the like.  Also added a positive
test case to ensure the full set works; this will obviously need updating as
we embellish the predefined types with things like required parameters.
2016-11-17 06:10:23 -08:00
joeduffy 065c900c2c Add a concept of "scopes"
This change introduces a binding scope structure, enabling names to be
bound to symbols using standard nested scopes.
2016-11-17 05:36:58 -08:00
joeduffy ad8195f1b5 Fix erroneous comments (Lookup*, not Bind*) 2016-11-16 19:08:41 -08:00
joeduffy 9c0c6e6916 Add rudimentary type binding
This change adds rudimentary type binding to phase 2 of the binder.  Note that
we still don't have the notion of predefined types (for the primitives), so this
basically rejects any well-formed Mufile.  Primitives are on deck.
2016-11-16 18:55:20 -08:00
joeduffy a4fdcaab68 Swap argument order to expected: actual: are correct 2016-11-16 18:51:14 -08:00
joeduffy 8daced40a1 Delete a garbage file
This seems to be leftover from before the diag package got a Document type.
2016-11-16 18:30:50 -08:00
joeduffy 6e70d01bf5 Fix diag.Sink errors/warnings count bug
This fixes a bug in diag.Sink where we didn't properly increment the
errors and warnings counts as they were issued.  Also added a regression test.
2016-11-16 17:52:14 -08:00
joeduffy b2d529a6f8 Place stack services underneath a "services" property
Instead of:

        name: mystack
        public:
                someservice
        private:
                someotherservice

we want it to be:

        name: mystack
        services:
                public:
                        someservice
                private
                        someotherservice

I had always intended it to be this way, but coded up the ASTs wrong.
2016-11-16 17:30:03 -08:00
joeduffy 109d8c3f4f Add a way to control logging verbosity
This change adds a --verbose=x flag (-v=x shorthand) to the Mu command,
to set the glog logging level to x, for all subcommands.
2016-11-16 17:19:49 -08:00
joeduffy c080ddbf46 Eliminate pointers from the parse tree
Neither the YAML nor JSON decoders appreciate having pointers in the AST
structures.  This is unfortunate because we end up mutating them later on.
Perhaps we will need separate parse trees and ASTs after all ...
2016-11-16 17:00:58 -08:00
joeduffy 832ef1f743 Lay some groundwork for symbol binding
This change lays some groundwork that registers symbols when doing semantic
analysis of the resulting AST.  For now, that just entails detecting duplicate
services by way of symbol registration.

Note that we've also split binding into two phases to account for the fact
that intra-stack dependencies are wholly legal.
2016-11-16 13:11:58 -08:00
joeduffy 917342f76f Decorate the AST with contextual info
This change decorates the AST with some information that is only known
after parsing.  This enables subsequent logic to remain context-free.
2016-11-16 11:51:50 -08:00
joeduffy 85a828fdf9 Use stable map enumeration for determinism
Go's map iteration order is undefined.  As such, anywhere we enumerate one
we need to go out of our way to sort the keys so that iteration is stable.
Unfortunately, this isn't a single line of code, as it would seem, due to
Go's lack of generics or even a reflectionless Keys() function on maps.  To
do this more elegently, I've created a new InOrderVisitor that handles the
stable enumeration so that other Visitors can remain simple and focus just
on the logic they need to get their job done.
2016-11-16 11:45:41 -08:00
joeduffy badf57c923 Type alias Dependency to SemVer, not string 2016-11-16 11:12:42 -08:00
joeduffy 2665a1a4c4 Check dependencies for validity
This change introduces a check during parse-tree analysis that dependencies
are valid, along with some tests.  Note that this could technically happen later
during semantic analysis and I will likely move it so that we can get better
diagnostics (more errors before failing).  I've also cleaned up and unified some
of the logic by introducing the general notion of a Visitor interface, which the
parse tree analyzer, binder, and analyzers to come will all implement.
2016-11-16 11:09:45 -08:00
joeduffy e2d04f7754 Add tests for parse tree validation
This adds a few tests for parse tree validation, and further restructures
the existing test logic.  The common_test.go file now contains helper methods
common to all tests in the mu/compiler package.  I've also adopted a naming
convention for the testdata/ directory to keep some sanity; namely, each
directory uses "(good|bad)_testname[_seqnum]" as a naming scheme.
2016-11-16 10:02:34 -08:00
joeduffy 1614258437 Declare a Mumodules constant
This is a placeholder for future use; .mu_modules will be our moral
equivalent to NPM/Yarn's node_modules directory.  I've chosen a dot
since for the most part developers can ignore its existence.
2016-11-16 10:01:46 -08:00
joeduffy 5a6c581a7e Check Stack semantic version numbers for correctness
This change ensures that Stack semantic version numbers specified in Mufiles
are correct.  Note that we do not accept ranges for the version number itself,
although obviously when checking dependencies we will permit it.
2016-11-16 10:00:52 -08:00
joeduffy 2dd8665c46 Prepare for semantic analysis
This change begins to lay the groundwork for doing semantic analysis and
lowering to the cloud target's representation.  In particular:

* Split the mu/schema package.  There is now mu/ast which contains the
  core types and mu/encoding which concerns itself with JSON and YAML
  serialization.

* Notably I am *not* yet introducing a second AST form.  Instead, we will
  keep the parse tree and AST unified for the time being.  I envision very
  little difference between them -- at least for now -- and so this keeps
  things simpler, at the expense of two downsides: 1) the trees will be
  mutable (which turns out to be a good thing for performance), and 2) some
  fields will need to be ignored during de/serialization.  We can always
  revisit this later when and if the need to split them arises.

* Add a binder phase.  It is currently a no-op.
2016-11-16 09:29:44 -08:00
joeduffy 60a1f02666 Add more compiler tests
This change adds a few more compiler tests and rearranges some bits and pieces
that came up while doing so.  For example, we now issue warnings for incorrect
casing and/or extensions of the Mufile (and test these conditions).  As part of
doing that, it became clear the layering between the mu/compiler and mu/workspace
packages wasn't quite right, so some logic got moved around; additionally, the
separation of concerns between mu/workspace and mu/schema wasn't quite right, so
this has been fixed also (workspace just understands Mufile related things while
schema understands how to unmarshal the specific supported extensions).
2016-11-16 08:19:26 -08:00
joeduffy 38c73b2e6a Add a simple compiler test
This change adds a compiler test that just checks the basic "Mufile is missing"
error checking.  The test itself is mostly uninteresting; what's more interesting
is the addition of some basic helper functionality that can be used for future
compiler tests, like capturing of compiler diagnostics for comparisons.
2016-11-15 19:16:02 -08:00
joeduffy 0ab10dd207 Rename Semver to SemVer
Eric rightly pointed out in a CR that Semver is...different.  Since it
is an abbreviation of the lengthier SemanticVersion name, SemVer seems
more appropriate.  Changed.
2016-11-15 18:34:19 -08:00
joeduffy 79f5f312b8 Support .yml Mufile extensions
This change recognizes .yml in addition to the official .yaml extension,
since .yml is actually very commonly used.  In addition, while in here, I've
centralized more of the extensions logic so that it's more "data-driven"
and easier to manage down the road (one place to change rather than two).
2016-11-15 18:26:21 -08:00
joeduffy ff0059cd7b Print relative filenames in errors
Error messages could get quite lengthy as the code was written previously,
because we always used the complete absolute path for the file in question.
This change "prettifies" this to be relative to whatever contextual path
the user has chosen during compilation.  This shortens messages considerably.
2016-11-15 18:00:43 -08:00
joeduffy c527cedb03 Delete api/types (missing from last commit) 2016-11-15 17:58:48 -08:00
joeduffy 094d3a0817 Perform more real compilation activities
This change includes some progress on actual compilation (albeit with several
TODOs remaining before we can actually spit out a useful artifact).  There are
also some general cleanups sprinkled throughout.  In a nutshell:

* Add a compiler.Context object that will be available during template expansion.

* Introduce a diag.Document abstraction.  This is better than passing raw filenames
  around, and lets us embellish diagnostics as we go.  In particular, we will be
  in a better position to provide line/column error information.

* Move IO out of the Parser and into the Compiler, where it can cache and reuse
  Documents.  This will become important as we start to load up dependencies.

* Rename PosRange to Location.  This reads nicer with the new Document terminology.

* Rename the mu/api package to mu/schema.  It's likely we will need to introduce a
  true AST that is decoupled from the serialization format and contains bound nodes.
  As a result, treating the existing types as "schema" is more honest.

* Add in a big section of TODOs at the end of the compiler.Compiler.Build function.
2016-11-15 17:42:22 -08:00
joeduffy d238ed61da Make a few improvements, mostly readability
* Rename Meta to Metadata.

* Rename Target's CloudOS and CloudScheduler properties to Cloud
  and Scheduler, respectively.  Also rename Target's JSON properties
  to match (they had drifted); they are now "cloud" and "scheduler".

* Rename Diags() to Diag() on the Compiler and Parser interfaces.

* Rename defaultDiags to defaultSink, to match the interface name.

* Add a few useful logging outputs.
2016-11-15 16:30:10 -08:00
joeduffy c928a0f60b Correctly recognize file extensions 2016-11-15 16:15:58 -08:00
joeduffy e75f06bb2b Sketch a mu build command and its scaffolding
This adds a bunch of general scaffolding and the beginning of a `build` command.

The general engineering scaffolding includes:

* Glide for dependency management.
* A Makefile that runs govet and golint during builds.
* Google's Glog library for logging.
* Cobra for command line functionality.

The Mu-specific scaffolding includes some packages:

* mu/pkg/diag: A package for compiler-like diagnostics.  It's fairly barebones
  at the moment, however we can embellish this over time.
* mu/pkg/errors: A package containing Mu's predefined set of errors.
* mu/pkg/workspace: A package containing workspace-related convenience helpers.

in addition to a main entrypoint that simply wires up and invokes the CLI.  From
there, the mu/cmd package takes over, with the Cobra-defined CLI commands.

Finally, the mu/pkg/compiler package actually implements the compiler behavior.
Or, it will.  For now, it simply parses a JSON or YAML Mufile into the core
mu/pkg/api types, and prints out the result.
2016-11-15 14:30:34 -05:00
joeduffy 9c7f774fc6 Project the core Mufile types
This change adds the core Mufile types (Cluster, Stack, and friends), including
mapping them to the relevant JSON names in the serialized form.  Notably absent
are all of the Identity-related types, which will come later on.
2016-11-15 14:28:17 -05:00