Add scaffolding for mu apply, compile, and plan
This adds scaffolding but no real functionality yet, as part of
marapongo/mu#41. I am landing this now because I need to take a
not-so-brief detour to gut and overhaul the core of the existing
compiler (parsing, semantic analysis, binding, code-gen, etc),
including merging the new pkg/pack contents back into the primary
top-level namespaces (like pkg/ast and pkg/encoding).
After that, I can begin driving the compiler to achieve the
desired effects of mu compile, first and foremost, and then plan
and apply later on.
2017-01-17 23:40:55 +01:00
|
|
|
// Copyright 2016 Marapongo, Inc. All rights reserved.
|
|
|
|
|
|
|
|
package cmd
|
|
|
|
|
|
|
|
import (
|
2017-02-13 23:26:46 +01:00
|
|
|
"fmt"
|
|
|
|
"os"
|
2017-02-17 02:32:13 +01:00
|
|
|
"strconv"
|
2017-02-13 23:26:46 +01:00
|
|
|
|
Add scaffolding for mu apply, compile, and plan
This adds scaffolding but no real functionality yet, as part of
marapongo/mu#41. I am landing this now because I need to take a
not-so-brief detour to gut and overhaul the core of the existing
compiler (parsing, semantic analysis, binding, code-gen, etc),
including merging the new pkg/pack contents back into the primary
top-level namespaces (like pkg/ast and pkg/encoding).
After that, I can begin driving the compiler to achieve the
desired effects of mu compile, first and foremost, and then plan
and apply later on.
2017-01-17 23:40:55 +01:00
|
|
|
"github.com/spf13/cobra"
|
2017-02-13 23:26:46 +01:00
|
|
|
|
2017-02-17 02:32:13 +01:00
|
|
|
"github.com/marapongo/mu/pkg/compiler/symbols"
|
2017-02-13 23:26:46 +01:00
|
|
|
"github.com/marapongo/mu/pkg/compiler/types"
|
|
|
|
"github.com/marapongo/mu/pkg/compiler/types/predef"
|
2017-02-17 02:32:13 +01:00
|
|
|
"github.com/marapongo/mu/pkg/eval/rt"
|
2017-02-13 23:26:46 +01:00
|
|
|
"github.com/marapongo/mu/pkg/graph"
|
Add scaffolding for mu apply, compile, and plan
This adds scaffolding but no real functionality yet, as part of
marapongo/mu#41. I am landing this now because I need to take a
not-so-brief detour to gut and overhaul the core of the existing
compiler (parsing, semantic analysis, binding, code-gen, etc),
including merging the new pkg/pack contents back into the primary
top-level namespaces (like pkg/ast and pkg/encoding).
After that, I can begin driving the compiler to achieve the
desired effects of mu compile, first and foremost, and then plan
and apply later on.
2017-01-17 23:40:55 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
func newPlanCmd() *cobra.Command {
|
|
|
|
var cmd = &cobra.Command{
|
|
|
|
Use: "plan [blueprint] [-- [args]]",
|
|
|
|
Short: "Generate a deployment plan from a Mu blueprint",
|
|
|
|
Long: "Generate a deployment plan from a Mu blueprint.\n" +
|
|
|
|
"\n" +
|
|
|
|
"A plan describes the overall graph and set of operations that will be performed\n" +
|
|
|
|
"as part of a Mu deployment. No actual resource creations, updates, or deletions\n" +
|
|
|
|
"will take place. This plan is as complete as possible without actually performing\n" +
|
|
|
|
"the operations described in the plan (with the caveat that conditional execution\n" +
|
|
|
|
"may obscure certain details, something that will be evident in plan's output).\n" +
|
|
|
|
"\n" +
|
|
|
|
"By default, a blueprint package is loaded from the current directory. Optionally,\n" +
|
|
|
|
"a path to a blueprint elsewhere can be provided as the [blueprint] argument.",
|
|
|
|
Run: func(cmd *cobra.Command, args []string) {
|
2017-02-13 23:26:46 +01:00
|
|
|
// Perform the compilation and, if non-nil is returned, output the plan.
|
|
|
|
if mugl := compile(cmd, args); mugl != nil {
|
2017-02-17 02:32:13 +01:00
|
|
|
printPlan(mugl)
|
2017-02-13 23:26:46 +01:00
|
|
|
}
|
Add scaffolding for mu apply, compile, and plan
This adds scaffolding but no real functionality yet, as part of
marapongo/mu#41. I am landing this now because I need to take a
not-so-brief detour to gut and overhaul the core of the existing
compiler (parsing, semantic analysis, binding, code-gen, etc),
including merging the new pkg/pack contents back into the primary
top-level namespaces (like pkg/ast and pkg/encoding).
After that, I can begin driving the compiler to achieve the
desired effects of mu compile, first and foremost, and then plan
and apply later on.
2017-01-17 23:40:55 +01:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
return cmd
|
|
|
|
}
|
2017-02-17 02:32:13 +01:00
|
|
|
|
|
|
|
func printPlan(mugl graph.Graph) {
|
|
|
|
// Sort the graph output so that it's a DAG.
|
|
|
|
// TODO: consider pruning out all non-resources so there is less to sort.
|
|
|
|
sorted, err := graph.TopSort(mugl)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Fprintf(os.Stderr, "fatal: %v\n", err)
|
|
|
|
os.Exit(-1)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now walk the elements and (for now), just print out which resources will be created.
|
|
|
|
for _, vert := range sorted {
|
|
|
|
o := vert.Obj()
|
|
|
|
t := o.Type()
|
|
|
|
if types.HasBaseName(t, predef.MuResourceClass) {
|
|
|
|
// Print the resource type.
|
|
|
|
fmt.Printf("+ %v:\n", t)
|
|
|
|
|
|
|
|
// Print all of the properties associated with this resource.
|
|
|
|
printProperties(o, " ")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func printProperties(obj *rt.Object, indent string) {
|
|
|
|
var keys []rt.PropertyKey
|
|
|
|
props := obj.PropertyValues()
|
|
|
|
|
|
|
|
// Compute the maximum with of property keys so we can justify everything.
|
|
|
|
maxkey := 0
|
|
|
|
for _, k := range rt.StablePropertyKeys(props) {
|
|
|
|
if isPrintableProperty(props[k]) {
|
|
|
|
keys = append(keys, k)
|
|
|
|
if len(k) > maxkey {
|
|
|
|
maxkey = len(k)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now print out the values intelligently based on the type.
|
|
|
|
for _, k := range keys {
|
|
|
|
fmt.Printf("%v%-"+strconv.Itoa(maxkey)+"s: ", indent, k)
|
|
|
|
printProperty(props[k].Obj(), indent)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func printProperty(obj *rt.Object, indent string) {
|
|
|
|
switch obj.Type() {
|
|
|
|
case types.Bool, types.Number, types.String:
|
|
|
|
fmt.Printf("%v\n", obj)
|
|
|
|
default:
|
|
|
|
switch obj.Type().(type) {
|
|
|
|
case *symbols.ArrayType:
|
|
|
|
fmt.Printf("[\n")
|
|
|
|
for i, elem := range *obj.ArrayValue() {
|
|
|
|
fmt.Printf("%v [%d]: ", indent, i)
|
|
|
|
printProperty(elem.Obj(), fmt.Sprintf(indent+" "))
|
|
|
|
}
|
|
|
|
fmt.Printf("%s]\n", indent)
|
|
|
|
default:
|
|
|
|
fmt.Printf("<%s> {\n", obj.Type())
|
|
|
|
printProperties(obj, indent+" ")
|
|
|
|
fmt.Printf("%s}\n", indent)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func isPrintableProperty(prop *rt.Pointer) bool {
|
|
|
|
_, isfunc := prop.Obj().Type().(*symbols.FunctionType)
|
|
|
|
return !isfunc
|
|
|
|
}
|