command: backup stuff works better

This commit is contained in:
Mitchell Hashimoto 2015-02-21 18:17:40 -08:00
parent b3aaf6feac
commit f81110c2fe
2 changed files with 47 additions and 15 deletions

View File

@ -40,20 +40,23 @@ type Meta struct {
color bool
oldUi cli.Ui
// The fields below are expected to be set by the command via
// command line flags. See the Apply command for an example.
//
// 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
//
// stateOutPath is used to override the output path for the state.
// If not provided, the StatePath is used causing the old state to
// be overriden.
stateOutPath string
//
// backupPath is used to backup the state file before writing a modified
// version. It defaults to stateOutPath + DefaultBackupExtention
backupPath string
statePath string
stateOutPath string
backupPath string
}
// initStatePaths is used to initialize the default values for
@ -123,12 +126,10 @@ func (m *Meta) Context(copts contextOpts) (*terraform.Context, bool, error) {
}
// Store the loaded state
state, statePath, err := State(m.statePath)
state, err := m.State()
if err != nil {
return nil, false, err
}
m.state = state
m.stateOutPath = statePath
// Load the root module
mod, err := module.NewTreeModule("", copts.Path)
@ -173,12 +174,17 @@ func (m *Meta) State() (state.State, error) {
return m.state, nil
}
state, _, err := State(m.statePath)
state, statePath, err := State(&StateOpts{
LocalPath: m.statePath,
LocalPathOut: m.stateOutPath,
BackupPath: m.backupPath,
})
if err != nil {
return nil, err
}
m.state = state
m.stateOutPath = statePath
return state, nil
}

View File

@ -11,13 +11,28 @@ import (
"github.com/hashicorp/terraform/terraform"
)
// StateOpts are options to get the state for a command.
type StateOpts struct {
// LocalPath is the path where the state is stored locally.
//
// LocalPathOut is the path where the local state will be saved. If this
// isn't set, it will be saved back to LocalPath.
LocalPath string
LocalPathOut string
// BackupPath is the path where the backup will be placed. If not set,
// it is assumed to be the path where the state is stored locally
// plus the DefaultBackupExtension.
BackupPath string
}
// State returns the proper state.State implementation to represent the
// current environment.
//
// localPath is the path to where state would be if stored locally.
// dataDir is the path to the local data directory where the remote state
// cache would be stored.
func State(localPath string) (state.State, string, error) {
func State(opts *StateOpts) (state.State, string, error) {
var result state.State
var resultPath string
@ -33,8 +48,11 @@ func State(localPath string) (state.State, string, error) {
}
// Do we have a local state?
if localPath != "" {
local := &state.LocalState{Path: localPath}
if opts.LocalPath != "" {
local := &state.LocalState{
Path: opts.LocalPath,
PathOut: opts.LocalPathOut,
}
err := local.RefreshState()
if err != nil {
isNotExist := false
@ -51,7 +69,7 @@ func State(localPath string) (state.State, string, error) {
// We already have a remote state... that is an error.
return nil, "", fmt.Errorf(
"Remote state found, but state file '%s' also present.",
localPath)
opts.LocalPath)
}
}
if err != nil {
@ -60,14 +78,22 @@ func State(localPath string) (state.State, string, error) {
}
result = local
resultPath = localPath
resultPath = opts.LocalPath
if opts.LocalPathOut != "" {
resultPath = opts.LocalPathOut
}
}
// If we have a result, make sure to back it up
if result != nil {
backupPath := resultPath + DefaultBackupExtention
if opts.BackupPath != "" {
backupPath = opts.BackupPath
}
result = &state.BackupState{
Real: result,
Path: resultPath + DefaultBackupExtention,
Path: backupPath,
}
}