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 }