diff --git a/command/state_meta.go b/command/state_meta.go index 2ac16385b..dc17fa073 100644 --- a/command/state_meta.go +++ b/command/state_meta.go @@ -18,46 +18,63 @@ type StateMeta struct{} // backups to be timestamped rather than just the original state path plus a // backup path. func (c *StateMeta) State(m *Meta) (state.State, error) { - // Load the backend - b, err := m.Backend(nil) - if err != nil { - return nil, err + var realState state.State + backupPath := m.backupPath + stateOutPath := m.statePath + + // use the specified state + if m.statePath != "" { + realState = &state.LocalState{ + Path: m.statePath, + } + } else { + // Load the backend + b, err := m.Backend(nil) + if err != nil { + return nil, err + } + + env := m.Workspace() + // Get the state + s, err := b.State(env) + if err != nil { + return nil, err + } + + // Get a local backend + localRaw, err := m.Backend(&BackendOpts{ForceLocal: true}) + if err != nil { + // This should never fail + panic(err) + } + localB := localRaw.(*backendlocal.Local) + _, stateOutPath, _ = localB.StatePaths(env) + if err != nil { + return nil, err + } + + realState = s } - env := m.Workspace() - // Get the state - s, err := b.State(env) - if err != nil { - return nil, err + // We always backup state commands, so set the back if none was specified + // (the default is "-", but some tests bypass the flag parsing). + if backupPath == "-" || backupPath == "" { + // Determine the backup path. stateOutPath is set to the resulting + // file where state is written (cached in the case of remote state) + backupPath = fmt.Sprintf( + "%s.%d%s", + stateOutPath, + time.Now().UTC().Unix(), + DefaultBackupExtension) } - // Get a local backend - localRaw, err := m.Backend(&BackendOpts{ForceLocal: true}) - if err != nil { - // This should never fail - panic(err) - } - localB := localRaw.(*backendlocal.Local) - _, stateOutPath, _ := localB.StatePaths(env) - if err != nil { - return nil, err - } - - // Determine the backup path. stateOutPath is set to the resulting - // file where state is written (cached in the case of remote state) - backupPath := fmt.Sprintf( - "%s.%d%s", - stateOutPath, - time.Now().UTC().Unix(), - DefaultBackupExtension) - // Wrap it for backups - s = &state.BackupState{ - Real: s, + realState = &state.BackupState{ + Real: realState, Path: backupPath, } - return s, nil + return realState, nil } // filterInstance filters a single instance out of filter results. diff --git a/command/state_mv_test.go b/command/state_mv_test.go index fe8102880..d3f05b31b 100644 --- a/command/state_mv_test.go +++ b/command/state_mv_test.go @@ -213,12 +213,7 @@ func TestStateMv_backupExplicit(t *testing.T) { // Test it is correct testStateOutput(t, statePath, testStateMvOutput) - // Test we have backups - backups := testStateBackups(t, filepath.Dir(statePath)) - if len(backups) != 1 { - t.Fatalf("bad: %#v", backups) - } - testStateOutput(t, backups[0], testStateMvOutputOriginal) + // Test backup testStateOutput(t, backupPath, testStateMvOutputOriginal) } diff --git a/command/state_rm_test.go b/command/state_rm_test.go index 22256366c..559ed09a9 100644 --- a/command/state_rm_test.go +++ b/command/state_rm_test.go @@ -130,12 +130,7 @@ func TestStateRm_backupExplicit(t *testing.T) { // Test it is correct testStateOutput(t, statePath, testStateRmOutput) - // Test we have backups - backups := testStateBackups(t, filepath.Dir(statePath)) - if len(backups) != 1 { - t.Fatalf("bad: %#v", backups) - } - testStateOutput(t, backups[0], testStateRmOutputOriginal) + // Test backup testStateOutput(t, backupPath, testStateRmOutputOriginal) }