2016-11-15 20:30:34 +01:00
|
|
|
// Copyright 2016 Marapongo, Inc. All rights reserved.
|
|
|
|
|
|
|
|
package cmd
|
|
|
|
|
|
|
|
import (
|
2016-11-17 16:00:52 +01:00
|
|
|
"fmt"
|
|
|
|
"os"
|
2016-11-16 03:26:21 +01:00
|
|
|
"path/filepath"
|
2016-11-17 16:00:52 +01:00
|
|
|
"strings"
|
2016-11-16 03:26:21 +01:00
|
|
|
|
|
|
|
"github.com/golang/glog"
|
2016-11-20 01:42:27 +01:00
|
|
|
"github.com/spf13/cobra"
|
|
|
|
|
2016-11-15 20:30:34 +01:00
|
|
|
"github.com/marapongo/mu/pkg/compiler"
|
2016-11-18 21:40:15 +01:00
|
|
|
"github.com/marapongo/mu/pkg/compiler/backends"
|
|
|
|
"github.com/marapongo/mu/pkg/compiler/backends/clouds"
|
|
|
|
"github.com/marapongo/mu/pkg/compiler/backends/schedulers"
|
2016-11-15 20:30:34 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
// defaultIn is where the Mu compiler looks for inputs by default.
|
|
|
|
const defaultInp = "."
|
|
|
|
|
|
|
|
// defaultOutput is where the Mu compiler places build artifacts by default.
|
|
|
|
const defaultOutp = ".mu"
|
|
|
|
|
|
|
|
func newBuildCmd() *cobra.Command {
|
|
|
|
var outp string
|
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 19:41:07 +01:00
|
|
|
var cluster string
|
2016-12-01 20:03:48 +01:00
|
|
|
var targetArch string
|
2016-12-07 05:49:54 +01:00
|
|
|
var skipCodegen bool
|
2016-11-15 20:30:34 +01:00
|
|
|
var cmd = &cobra.Command{
|
2016-11-30 00:27:02 +01:00
|
|
|
Use: "build [source] -- [args]",
|
2016-11-15 20:30:34 +01:00
|
|
|
Short: "Compile a Mu Stack",
|
|
|
|
Run: func(cmd *cobra.Command, args []string) {
|
2016-11-30 00:27:02 +01:00
|
|
|
flags := cmd.Flags()
|
|
|
|
ddash := flags.ArgsLenAtDash()
|
|
|
|
|
|
|
|
// If there's a --, we need to separate out the command args from the stack args.
|
|
|
|
var sargs []string
|
|
|
|
if ddash != -1 {
|
|
|
|
sargs = args[ddash:]
|
|
|
|
args = args[0:ddash]
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fetch the input source directory.
|
2016-11-15 20:30:34 +01:00
|
|
|
inp := defaultInp
|
|
|
|
if len(args) > 0 {
|
|
|
|
inp = args[0]
|
|
|
|
}
|
2016-11-16 03:26:21 +01:00
|
|
|
abs, err := filepath.Abs(inp)
|
|
|
|
if err != nil {
|
|
|
|
glog.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2016-11-17 16:00:52 +01:00
|
|
|
opts := compiler.DefaultOpts(abs)
|
2016-11-30 00:27:02 +01:00
|
|
|
|
2016-12-07 05:49:54 +01:00
|
|
|
if skipCodegen {
|
|
|
|
opts.SkipCodegen = true
|
|
|
|
}
|
|
|
|
|
2016-11-30 00:27:02 +01:00
|
|
|
// Set the cluster and architecture if specified.
|
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 19:41:07 +01:00
|
|
|
opts.Cluster = cluster
|
2016-12-09 21:42:28 +01:00
|
|
|
setCloudArchOptions(targetArch, opts)
|
2016-11-17 16:00:52 +01:00
|
|
|
|
2016-11-30 00:27:02 +01:00
|
|
|
// See if there are any arguments and, if so, accumulate them.
|
|
|
|
if len(sargs) > 0 {
|
|
|
|
opts.Args = make(map[string]string)
|
|
|
|
// TODO[marapongo/mu#7]: This is a very rudimentary parser. We can and should do better.
|
2016-12-06 00:59:28 +01:00
|
|
|
for i := 0; i < len(sargs); i++ {
|
|
|
|
sarg := sargs[i]
|
|
|
|
|
2016-11-30 00:27:02 +01:00
|
|
|
// Eat - or -- at the start.
|
|
|
|
if sarg[0] == '-' {
|
|
|
|
sarg = sarg[1:]
|
|
|
|
if sarg[0] == '-' {
|
|
|
|
sarg = sarg[1:]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Now find an k=v, and split the k/v part.
|
|
|
|
if eq := strings.IndexByte(sarg, '='); eq != -1 {
|
|
|
|
opts.Args[sarg[:eq]] = sarg[eq+1:]
|
|
|
|
} else {
|
2016-12-06 00:59:28 +01:00
|
|
|
// No =; if the next arg doesn't start with '-', use it. Else it must be a boolean "true".
|
|
|
|
if i+1 < len(sargs) && sargs[i+1][0] != '-' {
|
|
|
|
opts.Args[sarg] = sargs[i+1]
|
|
|
|
i++
|
|
|
|
} else {
|
|
|
|
// TODO(joe): support --no-key style "false"s.
|
|
|
|
opts.Args[sarg] = "true"
|
|
|
|
}
|
2016-11-30 00:27:02 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now new up a compiler and actually perform the build.
|
2016-11-17 16:00:52 +01:00
|
|
|
mup := compiler.NewCompiler(opts)
|
2016-11-16 03:26:21 +01:00
|
|
|
mup.Build(abs, outp)
|
2016-11-15 20:30:34 +01:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd.PersistentFlags().StringVar(
|
|
|
|
&outp, "out", defaultOutp,
|
2016-11-17 16:00:52 +01:00
|
|
|
"The directory in which to place build artifacts")
|
|
|
|
cmd.PersistentFlags().StringVarP(
|
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 19:41:07 +01:00
|
|
|
&cluster, "cluster", "c", "",
|
|
|
|
"Generate output for an existing, named cluster")
|
2016-12-01 20:03:48 +01:00
|
|
|
cmd.PersistentFlags().StringVarP(
|
|
|
|
&targetArch, "target", "t", "",
|
|
|
|
"Generate output for the target cloud architecture (format: \"cloud[:scheduler]\")")
|
2016-12-07 05:49:54 +01:00
|
|
|
cmd.PersistentFlags().BoolVar(
|
|
|
|
&skipCodegen, "skip-codegen", false,
|
|
|
|
"Skip code-generation phases of the compiler")
|
2016-11-15 20:30:34 +01:00
|
|
|
|
|
|
|
return cmd
|
|
|
|
}
|
2016-11-17 16:00:52 +01:00
|
|
|
|
2016-11-17 21:29:10 +01:00
|
|
|
func setCloudArchOptions(arch string, opts *compiler.Options) {
|
|
|
|
// If an architecture was specified, parse the pieces and set the options. This isn't required because stacks
|
|
|
|
// and workspaces can have defaults. This simply overrides or provides one where none exists.
|
|
|
|
if arch != "" {
|
2016-11-17 16:00:52 +01:00
|
|
|
// The format is "cloud[:scheduler]"; parse out the pieces.
|
|
|
|
var cloud string
|
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-19 01:46:36 +01:00
|
|
|
var scheduler string
|
2016-11-17 21:29:10 +01:00
|
|
|
if delim := strings.IndexRune(arch, ':'); delim != -1 {
|
|
|
|
cloud = arch[:delim]
|
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-19 01:46:36 +01:00
|
|
|
scheduler = arch[delim+1:]
|
2016-11-17 16:00:52 +01:00
|
|
|
} else {
|
2016-11-17 21:29:10 +01:00
|
|
|
cloud = arch
|
2016-11-17 16:00:52 +01:00
|
|
|
}
|
|
|
|
|
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-19 01:46:36 +01:00
|
|
|
cloudArch, ok := clouds.Values[cloud]
|
2016-11-17 16:00:52 +01:00
|
|
|
if !ok {
|
2016-11-17 21:29:10 +01:00
|
|
|
fmt.Fprintf(os.Stderr, "Unrecognized cloud arch '%v'\n", cloud)
|
2016-11-17 16:00:52 +01:00
|
|
|
os.Exit(-1)
|
|
|
|
}
|
|
|
|
|
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-19 01:46:36 +01:00
|
|
|
var schedulerArch schedulers.Arch
|
|
|
|
if scheduler != "" {
|
|
|
|
schedulerArch, ok = schedulers.Values[scheduler]
|
2016-11-17 16:00:52 +01:00
|
|
|
if !ok {
|
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-19 01:46:36 +01:00
|
|
|
fmt.Fprintf(os.Stderr, "Unrecognized cloud scheduler arch '%v'\n", scheduler)
|
2016-11-17 16:00:52 +01:00
|
|
|
os.Exit(-1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-18 21:40:15 +01:00
|
|
|
opts.Arch = backends.Arch{
|
2016-11-17 21:29:10 +01:00
|
|
|
Cloud: cloudArch,
|
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-19 01:46:36 +01:00
|
|
|
Scheduler: schedulerArch,
|
2016-11-17 16:00:52 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|