command: Get command, not functional yet. Converted to use modules.

This commit is contained in:
Mitchell Hashimoto 2014-09-22 10:56:50 -07:00
parent bea81d7710
commit ed538a9594
9 changed files with 192 additions and 14 deletions

View File

@ -68,7 +68,10 @@ func (c *ApplyCommand) Run(args []string) int {
}
// Build the context based on the arguments given
ctx, planned, err := c.Context(configPath, statePath)
ctx, planned, err := c.Context(contextOpts{
Path: configPath,
StatePath: statePath,
})
if err != nil {
c.Ui.Error(err.Error())
return 1

75
command/get.go Normal file
View File

@ -0,0 +1,75 @@
package command
import (
"flag"
"fmt"
"os"
"strings"
)
// GetCommand is a Command implementation that takes a Terraform
// configuration and downloads all the modules.
type GetCommand struct {
Meta
}
func (c *GetCommand) Run(args []string) int {
args = c.Meta.process(args, false)
cmdFlags := flag.NewFlagSet("get", flag.ContinueOnError)
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
if err := cmdFlags.Parse(args); err != nil {
return 1
}
var path string
args = cmdFlags.Args()
if len(args) > 1 {
c.Ui.Error("The graph command expects one argument.\n")
cmdFlags.Usage()
return 1
} else if len(args) == 1 {
path = args[0]
} else {
var err error
path, err = os.Getwd()
if err != nil {
c.Ui.Error(fmt.Sprintf("Error getting pwd: %s", err))
}
}
_, _, err := c.Context(contextOpts{
Path: path,
})
if err != nil {
c.Ui.Error(fmt.Sprintf("Error loading Terraform: %s", err))
return 1
}
return 0
}
func (c *GetCommand) Help() string {
helpText := `
Usage: terraform get [options] PATH
Downloads and installs modules needed for the configuration given by
PATH.
This recursively downloads all modules needed, such as modules
imported by modules imported by the root and so on. If a module is
already downloaded, it will not be redownloaded or checked for updates
unless the -update flag is specified.
Options:
-update=false If true, modules already downloaded will be checked
for updates and updated if necessary.
`
return strings.TrimSpace(helpText)
}
func (c *GetCommand) Synopsis() string {
return "Download and install modules for the configuration"
}

67
command/get_test.go Normal file
View File

@ -0,0 +1,67 @@
package command
import (
"os"
"testing"
"github.com/mitchellh/cli"
)
func TestGet(t *testing.T) {
ui := new(cli.MockUi)
c := &GetCommand{
Meta: Meta{
ContextOpts: testCtxConfig(testProvider()),
Ui: ui,
},
}
args := []string{
testFixturePath("graph"),
}
if code := c.Run(args); code != 0 {
t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
}
}
func TestGet_multipleArgs(t *testing.T) {
ui := new(cli.MockUi)
c := &GetCommand{
Meta: Meta{
ContextOpts: testCtxConfig(testProvider()),
Ui: ui,
},
}
args := []string{
"bad",
"bad",
}
if code := c.Run(args); code != 1 {
t.Fatalf("bad: \n%s", ui.OutputWriter.String())
}
}
func TestGet_noArgs(t *testing.T) {
cwd, err := os.Getwd()
if err != nil {
t.Fatalf("err: %s", err)
}
if err := os.Chdir(testFixturePath("graph")); err != nil {
t.Fatalf("err: %s", err)
}
defer os.Chdir(cwd)
ui := new(cli.MockUi)
c := &GraphCommand{
Meta: Meta{
ContextOpts: testCtxConfig(testProvider()),
Ui: ui,
},
}
args := []string{}
if code := c.Run(args); code != 0 {
t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
}
}

View File

@ -40,7 +40,10 @@ func (c *GraphCommand) Run(args []string) int {
}
}
ctx, _, err := c.Context(path, "")
ctx, _, err := c.Context(contextOpts{
Path: path,
StatePath: "",
})
if err != nil {
c.Ui.Error(fmt.Sprintf("Error loading Terraform: %s", err))
return 1

View File

@ -7,7 +7,7 @@ import (
"io"
"os"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/config/module"
"github.com/hashicorp/terraform/terraform"
"github.com/mitchellh/cli"
"github.com/mitchellh/colorstring"
@ -46,11 +46,11 @@ func (m *Meta) Colorize() *colorstring.Colorize {
// Context returns a Terraform Context taking into account the context
// options used to initialize this meta configuration.
func (m *Meta) Context(path, statePath string) (*terraform.Context, bool, error) {
func (m *Meta) Context(copts contextOpts) (*terraform.Context, bool, error) {
opts := m.contextOpts()
// First try to just read the plan directly from the path given.
f, err := os.Open(path)
f, err := os.Open(copts.Path)
if err == nil {
plan, err := terraform.ReadPlan(f)
f.Close()
@ -69,8 +69,8 @@ func (m *Meta) Context(path, statePath string) (*terraform.Context, bool, error)
// Load up the state
var state *terraform.State
if statePath != "" {
f, err := os.Open(statePath)
if copts.StatePath != "" {
f, err := os.Open(copts.StatePath)
if err != nil && os.IsNotExist(err) {
// If the state file doesn't exist, it is okay, since it
// is probably a new infrastructure.
@ -88,15 +88,13 @@ func (m *Meta) Context(path, statePath string) (*terraform.Context, bool, error)
// Store the loaded state
m.state = state
config, err := config.LoadDir(path)
// Load the root module
mod, err := module.NewTreeModule("", copts.Path)
if err != nil {
return nil, false, fmt.Errorf("Error loading config: %s", err)
}
if err := config.Validate(); err != nil {
return nil, false, fmt.Errorf("Error validating config: %s", err)
}
opts.Config = config
opts.Config = mod.Config()
opts.State = state
ctx := terraform.NewContext(opts)
return ctx, false, nil
@ -207,3 +205,18 @@ func (m *Meta) uiHook() *UiHook {
Ui: m.Ui,
}
}
// contextOpts are the options used to load a context from a command.
type contextOpts struct {
// Path to the directory where the root module is.
Path string
// StatePath is the path to the state file. If this is empty, then
// no state will be loaded. It is also okay for this to be a path to
// a file that doesn't exist; it is assumed that this means that there
// is simply no state.
StatePath string
// GetMode is the module.GetMode to use when loading the module tree.
GetMode module.GetMode
}

View File

@ -65,7 +65,10 @@ func (c *PlanCommand) Run(args []string) int {
backupPath = statePath + DefaultBackupExtention
}
ctx, _, err := c.Context(path, statePath)
ctx, _, err := c.Context(contextOpts{
Path: path,
StatePath: statePath,
})
if err != nil {
c.Ui.Error(err.Error())
return 1

View File

@ -84,7 +84,10 @@ func (c *RefreshCommand) Run(args []string) int {
}
// Build the context based on the arguments given
ctx, _, err := c.Context(configPath, statePath)
ctx, _, err := c.Context(contextOpts{
Path: configPath,
StatePath: statePath,
})
if err != nil {
c.Ui.Error(err.Error())
return 1

View File

@ -40,6 +40,12 @@ func init() {
}, nil
},
"get": func() (cli.Command, error) {
return &command.GetCommand{
Meta: meta,
}, nil
},
"graph": func() (cli.Command, error) {
return &command.GraphCommand{
Meta: meta,

View File

@ -58,6 +58,11 @@ func NewTreeModule(name, dir string) (*Tree, error) {
return NewTree(name, c), nil
}
// Config returns the configuration for this module.
func (t *Tree) Config() *config.Config {
return t.config
}
// Children returns the children of this tree (the modules that are
// imported by this root).
//