mirror of
https://github.com/hashicorp/terraform.git
synced 2026-02-20 00:13:30 -05:00
91 lines
3.1 KiB
Go
91 lines
3.1 KiB
Go
// Copyright IBM Corp. 2014, 2026
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package stackmigrate
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"log"
|
|
"net/url"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/hashicorp/terraform/internal/backend"
|
|
"github.com/hashicorp/terraform/internal/backend/local"
|
|
"github.com/hashicorp/terraform/internal/command/workdir"
|
|
)
|
|
|
|
type Meta struct {
|
|
// WorkingDir is an object representing the "working directory" where we're
|
|
// running commands. In the normal case this literally refers to the
|
|
// working directory of the Terraform process, though this can take on
|
|
// a more symbolic meaning when the user has overridden default behavior
|
|
// to specify a different working directory or to override the special
|
|
// data directory where we'll persist settings that must survive between
|
|
// consecutive commands.
|
|
WorkingDir *workdir.Dir
|
|
}
|
|
|
|
var errInvalidWorkspaceNameEnvVar = fmt.Errorf("Invalid workspace name set using %s", WorkspaceNameEnvVar)
|
|
|
|
// Workspace returns the name of the currently configured workspace, corresponding
|
|
// to the desired named state.
|
|
func (m *Meta) Workspace() (string, error) {
|
|
current, overridden := m.WorkspaceOverridden()
|
|
if overridden && !validWorkspaceName(current) {
|
|
return "", errInvalidWorkspaceNameEnvVar
|
|
}
|
|
return current, nil
|
|
}
|
|
|
|
// WorkspaceOverridden returns the name of the currently configured workspace,
|
|
// corresponding to the desired named state, as well as a bool saying whether
|
|
// this was set via the TF_WORKSPACE environment variable.
|
|
func (m *Meta) WorkspaceOverridden() (string, bool) {
|
|
if envVar := os.Getenv(WorkspaceNameEnvVar); envVar != "" {
|
|
return envVar, true
|
|
}
|
|
|
|
envData, err := ioutil.ReadFile(filepath.Join(m.DataDir(), local.DefaultWorkspaceFile))
|
|
current := string(bytes.TrimSpace(envData))
|
|
if current == "" {
|
|
current = backend.DefaultStateName
|
|
}
|
|
|
|
if err != nil && !os.IsNotExist(err) {
|
|
// always return the default if we can't get a workspace name
|
|
log.Printf("[ERROR] failed to read current workspace: %s", err)
|
|
}
|
|
|
|
return current, false
|
|
}
|
|
|
|
// fixupMissingWorkingDir is a compensation for various existing tests which
|
|
// directly construct incomplete "Meta" objects. Specifically, it deals with
|
|
// a test that omits a WorkingDir value by constructing one just-in-time.
|
|
//
|
|
// We shouldn't ever rely on this in any real codepath, because it doesn't
|
|
// take into account the various ways users can override our default
|
|
// directory selection behaviors.
|
|
func (m *Meta) fixupMissingWorkingDir() {
|
|
if m.WorkingDir == nil {
|
|
log.Printf("[WARN] This 'Meta' object is missing its WorkingDir, so we're creating a default one suitable only for tests")
|
|
m.WorkingDir = workdir.NewDir(".")
|
|
}
|
|
}
|
|
|
|
// DataDir returns the directory where local data will be stored.
|
|
// Defaults to DefaultDataDir in the current working directory.
|
|
func (m *Meta) DataDir() string {
|
|
m.fixupMissingWorkingDir()
|
|
return m.WorkingDir.DataDir()
|
|
}
|
|
|
|
// validWorkspaceName returns true is this name is valid to use as a workspace name.
|
|
// Since most named states are accessed via a filesystem path or URL, check if
|
|
// escaping the name would be required.
|
|
func validWorkspaceName(name string) bool {
|
|
return name == url.PathEscape(name)
|
|
}
|