In some cases, we want to specialize template generation based on the options passed to the compiler. This change flows them through so that they can be accessed as {{if .Options.SomeSetting}} ... {{end}}
152 lines
4 KiB
Go
152 lines
4 KiB
Go
// Copyright 2016 Marapongo, Inc. All rights reserved.
|
|
|
|
package cmd
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/golang/glog"
|
|
"github.com/spf13/cobra"
|
|
|
|
"github.com/marapongo/mu/pkg/compiler"
|
|
"github.com/marapongo/mu/pkg/compiler/backends"
|
|
"github.com/marapongo/mu/pkg/compiler/backends/clouds"
|
|
"github.com/marapongo/mu/pkg/compiler/backends/schedulers"
|
|
)
|
|
|
|
// 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
|
|
var cluster string
|
|
var targetArch string
|
|
var skipCodegen bool
|
|
var cmd = &cobra.Command{
|
|
Use: "build [source] -- [args]",
|
|
Short: "Compile a Mu Stack",
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
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.
|
|
inp := defaultInp
|
|
if len(args) > 0 {
|
|
inp = args[0]
|
|
}
|
|
abs, err := filepath.Abs(inp)
|
|
if err != nil {
|
|
glog.Fatal(err)
|
|
}
|
|
|
|
opts := compiler.DefaultOpts(abs)
|
|
|
|
if skipCodegen {
|
|
opts.SkipCodegen = true
|
|
}
|
|
|
|
// Set the cluster and architecture if specified.
|
|
opts.Cluster = cluster
|
|
setCloudArchOptions(targetArch, opts)
|
|
|
|
// 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.
|
|
for i := 0; i < len(sargs); i++ {
|
|
sarg := sargs[i]
|
|
|
|
// 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 {
|
|
// 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"
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// Now new up a compiler and actually perform the build.
|
|
mup := compiler.NewCompiler(opts)
|
|
mup.Build(abs, outp)
|
|
},
|
|
}
|
|
|
|
cmd.PersistentFlags().StringVar(
|
|
&outp, "out", defaultOutp,
|
|
"The directory in which to place build artifacts")
|
|
cmd.PersistentFlags().StringVarP(
|
|
&cluster, "cluster", "c", "",
|
|
"Generate output for an existing, named cluster")
|
|
cmd.PersistentFlags().StringVarP(
|
|
&targetArch, "target", "t", "",
|
|
"Generate output for the target cloud architecture (format: \"cloud[:scheduler]\")")
|
|
cmd.PersistentFlags().BoolVar(
|
|
&skipCodegen, "skip-codegen", false,
|
|
"Skip code-generation phases of the compiler")
|
|
|
|
return cmd
|
|
}
|
|
|
|
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 != "" {
|
|
// The format is "cloud[:scheduler]"; parse out the pieces.
|
|
var cloud string
|
|
var scheduler string
|
|
if delim := strings.IndexRune(arch, ':'); delim != -1 {
|
|
cloud = arch[:delim]
|
|
scheduler = arch[delim+1:]
|
|
} else {
|
|
cloud = arch
|
|
}
|
|
|
|
cloudArch, ok := clouds.Values[cloud]
|
|
if !ok {
|
|
fmt.Fprintf(os.Stderr, "Unrecognized cloud arch '%v'\n", cloud)
|
|
os.Exit(-1)
|
|
}
|
|
|
|
var schedulerArch schedulers.Arch
|
|
if scheduler != "" {
|
|
schedulerArch, ok = schedulers.Values[scheduler]
|
|
if !ok {
|
|
fmt.Fprintf(os.Stderr, "Unrecognized cloud scheduler arch '%v'\n", scheduler)
|
|
os.Exit(-1)
|
|
}
|
|
}
|
|
|
|
opts.Arch = backends.Arch{
|
|
Cloud: cloudArch,
|
|
Scheduler: schedulerArch,
|
|
}
|
|
}
|
|
}
|