github.com/opentofu/opentofu@v1.7.1/internal/command/workspace_select.go (about)

     1  // Copyright (c) The OpenTofu Authors
     2  // SPDX-License-Identifier: MPL-2.0
     3  // Copyright (c) 2023 HashiCorp, Inc.
     4  // SPDX-License-Identifier: MPL-2.0
     5  
     6  package command
     7  
     8  import (
     9  	"fmt"
    10  	"strings"
    11  
    12  	"github.com/mitchellh/cli"
    13  	"github.com/posener/complete"
    14  
    15  	"github.com/opentofu/opentofu/internal/tfdiags"
    16  )
    17  
    18  type WorkspaceSelectCommand struct {
    19  	Meta
    20  	LegacyName bool
    21  }
    22  
    23  func (c *WorkspaceSelectCommand) Run(args []string) int {
    24  	args = c.Meta.process(args)
    25  	envCommandShowWarning(c.Ui, c.LegacyName)
    26  
    27  	var orCreate bool
    28  	cmdFlags := c.Meta.defaultFlagSet("workspace select")
    29  	cmdFlags.BoolVar(&orCreate, "or-create", false, "create workspace if it does not exist")
    30  	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
    31  	if err := cmdFlags.Parse(args); err != nil {
    32  		c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
    33  		return 1
    34  	}
    35  
    36  	args = cmdFlags.Args()
    37  	if len(args) != 1 {
    38  		c.Ui.Error("Expected a single argument: NAME.\n")
    39  		return cli.RunResultHelp
    40  	}
    41  
    42  	configPath, err := modulePath(args[1:])
    43  	if err != nil {
    44  		c.Ui.Error(err.Error())
    45  		return 1
    46  	}
    47  
    48  	var diags tfdiags.Diagnostics
    49  
    50  	backendConfig, backendDiags := c.loadBackendConfig(configPath)
    51  	diags = diags.Append(backendDiags)
    52  	if diags.HasErrors() {
    53  		c.showDiagnostics(diags)
    54  		return 1
    55  	}
    56  
    57  	current, isOverridden := c.WorkspaceOverridden()
    58  	if isOverridden {
    59  		c.Ui.Error(envIsOverriddenSelectError)
    60  		return 1
    61  	}
    62  
    63  	// Load the encryption configuration
    64  	enc, encDiags := c.EncryptionFromPath(configPath)
    65  	diags = diags.Append(encDiags)
    66  	if encDiags.HasErrors() {
    67  		c.showDiagnostics(diags)
    68  		return 1
    69  	}
    70  
    71  	// Load the backend
    72  	b, backendDiags := c.Backend(&BackendOpts{
    73  		Config: backendConfig,
    74  	}, enc.State())
    75  	diags = diags.Append(backendDiags)
    76  	if backendDiags.HasErrors() {
    77  		c.showDiagnostics(diags)
    78  		return 1
    79  	}
    80  
    81  	if err != nil {
    82  		c.Ui.Error(fmt.Sprintf("Failed to load backend: %s", err))
    83  		return 1
    84  	}
    85  
    86  	// This command will not write state
    87  	c.ignoreRemoteVersionConflict(b)
    88  
    89  	name := args[0]
    90  	if !validWorkspaceName(name) {
    91  		c.Ui.Error(fmt.Sprintf(envInvalidName, name))
    92  		return 1
    93  	}
    94  
    95  	states, err := b.Workspaces()
    96  	if err != nil {
    97  		c.Ui.Error(err.Error())
    98  		return 1
    99  	}
   100  
   101  	if name == current {
   102  		// already using this workspace
   103  		return 0
   104  	}
   105  
   106  	found := false
   107  	for _, s := range states {
   108  		if name == s {
   109  			found = true
   110  			break
   111  		}
   112  	}
   113  
   114  	var newState bool
   115  
   116  	if !found {
   117  		if orCreate {
   118  			_, err = b.StateMgr(name)
   119  			if err != nil {
   120  				c.Ui.Error(err.Error())
   121  				return 1
   122  			}
   123  			newState = true
   124  		} else {
   125  			c.Ui.Error(fmt.Sprintf(envDoesNotExist, name))
   126  			return 1
   127  		}
   128  	}
   129  
   130  	err = c.SetWorkspace(name)
   131  	if err != nil {
   132  		c.Ui.Error(err.Error())
   133  		return 1
   134  	}
   135  
   136  	if newState {
   137  		c.Ui.Output(c.Colorize().Color(fmt.Sprintf(
   138  			strings.TrimSpace(envCreated), name)))
   139  	} else {
   140  		c.Ui.Output(
   141  			c.Colorize().Color(
   142  				fmt.Sprintf(envChanged, name),
   143  			),
   144  		)
   145  	}
   146  
   147  	return 0
   148  }
   149  
   150  func (c *WorkspaceSelectCommand) AutocompleteArgs() complete.Predictor {
   151  	return completePredictSequence{
   152  		c.completePredictWorkspaceName(),
   153  		complete.PredictDirs(""),
   154  	}
   155  }
   156  
   157  func (c *WorkspaceSelectCommand) AutocompleteFlags() complete.Flags {
   158  	return nil
   159  }
   160  
   161  func (c *WorkspaceSelectCommand) Help() string {
   162  	helpText := `
   163  Usage: tofu [global options] workspace select NAME
   164  
   165    Select a different OpenTofu workspace.
   166  
   167  Options:
   168  
   169      -or-create=false    Create the OpenTofu workspace if it doesn't exist.
   170  
   171  `
   172  	return strings.TrimSpace(helpText)
   173  }
   174  
   175  func (c *WorkspaceSelectCommand) Synopsis() string {
   176  	return "Select a workspace"
   177  }