pulumi/cmd/build.go

153 lines
4 KiB
Go
Raw Normal View History

// 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,
}
}
}