Skip to content

Commit

Permalink
command: Get command, not functional yet. Converted to use modules.
Browse files Browse the repository at this point in the history
  • Loading branch information
mitchellh committed Sep 22, 2014
1 parent bea81d7 commit ed538a9
Show file tree
Hide file tree
Showing 9 changed files with 192 additions and 14 deletions.
5 changes: 4 additions & 1 deletion command/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
75 changes: 75 additions & 0 deletions command/get.go
Original file line number Diff line number Diff line change
@@ -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 changes: 67 additions & 0 deletions command/get_test.go
Original file line number Diff line number Diff line change
@@ -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())
}
}
5 changes: 4 additions & 1 deletion command/graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
33 changes: 23 additions & 10 deletions command/meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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()
Expand All @@ -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.
Expand All @@ -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
Expand Down Expand Up @@ -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
}
5 changes: 4 additions & 1 deletion command/plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 4 additions & 1 deletion command/refresh.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
5 changes: 5 additions & 0 deletions config/module/tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -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).
//
Expand Down

0 comments on commit ed538a9

Please sign in to comment.