github.com/pulumi/terraform@v1.4.0/commands.go (about)

     1  package main
     2  
     3  import (
     4  	"os"
     5  	"os/signal"
     6  
     7  	"github.com/mitchellh/cli"
     8  
     9  	"github.com/hashicorp/go-plugin"
    10  	svchost "github.com/hashicorp/terraform-svchost"
    11  	"github.com/hashicorp/terraform-svchost/auth"
    12  	"github.com/hashicorp/terraform-svchost/disco"
    13  	"github.com/pulumi/terraform/pkg/addrs"
    14  	"github.com/pulumi/terraform/pkg/command"
    15  	"github.com/pulumi/terraform/pkg/command/cliconfig"
    16  	"github.com/pulumi/terraform/pkg/command/views"
    17  	"github.com/pulumi/terraform/pkg/command/webbrowser"
    18  	"github.com/pulumi/terraform/pkg/getproviders"
    19  	pluginDiscovery "github.com/pulumi/terraform/pkg/plugin/discovery"
    20  	"github.com/pulumi/terraform/pkg/terminal"
    21  )
    22  
    23  // runningInAutomationEnvName gives the name of an environment variable that
    24  // can be set to any non-empty value in order to suppress certain messages
    25  // that assume that Terraform is being run from a command prompt.
    26  const runningInAutomationEnvName = "TF_IN_AUTOMATION"
    27  
    28  // Commands is the mapping of all the available Terraform commands.
    29  var Commands map[string]cli.CommandFactory
    30  
    31  // PrimaryCommands is an ordered sequence of the top-level commands (not
    32  // subcommands) that we emphasize at the top of our help output. This is
    33  // ordered so that we can show them in the typical workflow order, rather
    34  // than in alphabetical order. Anything not in this sequence or in the
    35  // HiddenCommands set appears under "all other commands".
    36  var PrimaryCommands []string
    37  
    38  // HiddenCommands is a set of top-level commands (not subcommands) that are
    39  // not advertised in the top-level help at all. This is typically because
    40  // they are either just stubs that return an error message about something
    41  // no longer being supported or backward-compatibility aliases for other
    42  // commands.
    43  //
    44  // No commands in the PrimaryCommands sequence should also appear in the
    45  // HiddenCommands set, because that would be rather silly.
    46  var HiddenCommands map[string]struct{}
    47  
    48  // Ui is the cli.Ui used for communicating to the outside world.
    49  var Ui cli.Ui
    50  
    51  func initCommands(
    52  	originalWorkingDir string,
    53  	streams *terminal.Streams,
    54  	config *cliconfig.Config,
    55  	services *disco.Disco,
    56  	providerSrc getproviders.Source,
    57  	providerDevOverrides map[addrs.Provider]getproviders.PackageLocalDir,
    58  	unmanagedProviders map[addrs.Provider]*plugin.ReattachConfig,
    59  ) {
    60  	var inAutomation bool
    61  	if v := os.Getenv(runningInAutomationEnvName); v != "" {
    62  		inAutomation = true
    63  	}
    64  
    65  	for userHost, hostConfig := range config.Hosts {
    66  		host, err := svchost.ForComparison(userHost)
    67  		if err != nil {
    68  			// We expect the config was already validated by the time we get
    69  			// here, so we'll just ignore invalid hostnames.
    70  			continue
    71  		}
    72  		services.ForceHostServices(host, hostConfig.Services)
    73  	}
    74  
    75  	configDir, err := cliconfig.ConfigDir()
    76  	if err != nil {
    77  		configDir = "" // No config dir available (e.g. looking up a home directory failed)
    78  	}
    79  
    80  	wd := WorkingDir(originalWorkingDir, os.Getenv("TF_DATA_DIR"))
    81  
    82  	meta := command.Meta{
    83  		WorkingDir: wd,
    84  		Streams:    streams,
    85  		View:       views.NewView(streams).SetRunningInAutomation(inAutomation),
    86  
    87  		Color:            true,
    88  		GlobalPluginDirs: globalPluginDirs(),
    89  		Ui:               Ui,
    90  
    91  		Services:        services,
    92  		BrowserLauncher: webbrowser.NewNativeLauncher(),
    93  
    94  		RunningInAutomation: inAutomation,
    95  		CLIConfigDir:        configDir,
    96  		PluginCacheDir:      config.PluginCacheDir,
    97  
    98  		PluginCacheMayBreakDependencyLockFile: config.PluginCacheMayBreakDependencyLockFile,
    99  
   100  		ShutdownCh: makeShutdownCh(),
   101  
   102  		ProviderSource:       providerSrc,
   103  		ProviderDevOverrides: providerDevOverrides,
   104  		UnmanagedProviders:   unmanagedProviders,
   105  
   106  		AllowExperimentalFeatures: ExperimentsAllowed(),
   107  	}
   108  
   109  	// The command list is included in the terraform -help
   110  	// output, which is in turn included in the docs at
   111  	// website/docs/cli/commands/index.html.markdown; if you
   112  	// add, remove or reclassify commands then consider updating
   113  	// that to match.
   114  
   115  	Commands = map[string]cli.CommandFactory{
   116  		"apply": func() (cli.Command, error) {
   117  			return &command.ApplyCommand{
   118  				Meta: meta,
   119  			}, nil
   120  		},
   121  
   122  		"console": func() (cli.Command, error) {
   123  			return &command.ConsoleCommand{
   124  				Meta: meta,
   125  			}, nil
   126  		},
   127  
   128  		"destroy": func() (cli.Command, error) {
   129  			return &command.ApplyCommand{
   130  				Meta:    meta,
   131  				Destroy: true,
   132  			}, nil
   133  		},
   134  
   135  		"env": func() (cli.Command, error) {
   136  			return &command.WorkspaceCommand{
   137  				Meta:       meta,
   138  				LegacyName: true,
   139  			}, nil
   140  		},
   141  
   142  		"env list": func() (cli.Command, error) {
   143  			return &command.WorkspaceListCommand{
   144  				Meta:       meta,
   145  				LegacyName: true,
   146  			}, nil
   147  		},
   148  
   149  		"env select": func() (cli.Command, error) {
   150  			return &command.WorkspaceSelectCommand{
   151  				Meta:       meta,
   152  				LegacyName: true,
   153  			}, nil
   154  		},
   155  
   156  		"env new": func() (cli.Command, error) {
   157  			return &command.WorkspaceNewCommand{
   158  				Meta:       meta,
   159  				LegacyName: true,
   160  			}, nil
   161  		},
   162  
   163  		"env delete": func() (cli.Command, error) {
   164  			return &command.WorkspaceDeleteCommand{
   165  				Meta:       meta,
   166  				LegacyName: true,
   167  			}, nil
   168  		},
   169  
   170  		"fmt": func() (cli.Command, error) {
   171  			return &command.FmtCommand{
   172  				Meta: meta,
   173  			}, nil
   174  		},
   175  
   176  		"get": func() (cli.Command, error) {
   177  			return &command.GetCommand{
   178  				Meta: meta,
   179  			}, nil
   180  		},
   181  
   182  		"graph": func() (cli.Command, error) {
   183  			return &command.GraphCommand{
   184  				Meta: meta,
   185  			}, nil
   186  		},
   187  
   188  		"import": func() (cli.Command, error) {
   189  			return &command.ImportCommand{
   190  				Meta: meta,
   191  			}, nil
   192  		},
   193  
   194  		"init": func() (cli.Command, error) {
   195  			return &command.InitCommand{
   196  				Meta: meta,
   197  			}, nil
   198  		},
   199  
   200  		"login": func() (cli.Command, error) {
   201  			return &command.LoginCommand{
   202  				Meta: meta,
   203  			}, nil
   204  		},
   205  
   206  		"logout": func() (cli.Command, error) {
   207  			return &command.LogoutCommand{
   208  				Meta: meta,
   209  			}, nil
   210  		},
   211  
   212  		"metadata": func() (cli.Command, error) {
   213  			return &command.MetadataCommand{
   214  				Meta: meta,
   215  			}, nil
   216  		},
   217  
   218  		"metadata functions": func() (cli.Command, error) {
   219  			return &command.MetadataFunctionsCommand{
   220  				Meta: meta,
   221  			}, nil
   222  		},
   223  
   224  		"output": func() (cli.Command, error) {
   225  			return &command.OutputCommand{
   226  				Meta: meta,
   227  			}, nil
   228  		},
   229  
   230  		"plan": func() (cli.Command, error) {
   231  			return &command.PlanCommand{
   232  				Meta: meta,
   233  			}, nil
   234  		},
   235  
   236  		"providers": func() (cli.Command, error) {
   237  			return &command.ProvidersCommand{
   238  				Meta: meta,
   239  			}, nil
   240  		},
   241  
   242  		"providers lock": func() (cli.Command, error) {
   243  			return &command.ProvidersLockCommand{
   244  				Meta: meta,
   245  			}, nil
   246  		},
   247  
   248  		"providers mirror": func() (cli.Command, error) {
   249  			return &command.ProvidersMirrorCommand{
   250  				Meta: meta,
   251  			}, nil
   252  		},
   253  
   254  		"providers schema": func() (cli.Command, error) {
   255  			return &command.ProvidersSchemaCommand{
   256  				Meta: meta,
   257  			}, nil
   258  		},
   259  
   260  		"push": func() (cli.Command, error) {
   261  			return &command.PushCommand{
   262  				Meta: meta,
   263  			}, nil
   264  		},
   265  
   266  		"refresh": func() (cli.Command, error) {
   267  			return &command.RefreshCommand{
   268  				Meta: meta,
   269  			}, nil
   270  		},
   271  
   272  		"show": func() (cli.Command, error) {
   273  			return &command.ShowCommand{
   274  				Meta: meta,
   275  			}, nil
   276  		},
   277  
   278  		"taint": func() (cli.Command, error) {
   279  			return &command.TaintCommand{
   280  				Meta: meta,
   281  			}, nil
   282  		},
   283  
   284  		"test": func() (cli.Command, error) {
   285  			return &command.TestCommand{
   286  				Meta: meta,
   287  			}, nil
   288  		},
   289  
   290  		"validate": func() (cli.Command, error) {
   291  			return &command.ValidateCommand{
   292  				Meta: meta,
   293  			}, nil
   294  		},
   295  
   296  		"version": func() (cli.Command, error) {
   297  			return &command.VersionCommand{
   298  				Meta:              meta,
   299  				Version:           Version,
   300  				VersionPrerelease: VersionPrerelease,
   301  				Platform:          getproviders.CurrentPlatform,
   302  				CheckFunc:         commandVersionCheck,
   303  			}, nil
   304  		},
   305  
   306  		"untaint": func() (cli.Command, error) {
   307  			return &command.UntaintCommand{
   308  				Meta: meta,
   309  			}, nil
   310  		},
   311  
   312  		"workspace": func() (cli.Command, error) {
   313  			return &command.WorkspaceCommand{
   314  				Meta: meta,
   315  			}, nil
   316  		},
   317  
   318  		"workspace list": func() (cli.Command, error) {
   319  			return &command.WorkspaceListCommand{
   320  				Meta: meta,
   321  			}, nil
   322  		},
   323  
   324  		"workspace select": func() (cli.Command, error) {
   325  			return &command.WorkspaceSelectCommand{
   326  				Meta: meta,
   327  			}, nil
   328  		},
   329  
   330  		"workspace show": func() (cli.Command, error) {
   331  			return &command.WorkspaceShowCommand{
   332  				Meta: meta,
   333  			}, nil
   334  		},
   335  
   336  		"workspace new": func() (cli.Command, error) {
   337  			return &command.WorkspaceNewCommand{
   338  				Meta: meta,
   339  			}, nil
   340  		},
   341  
   342  		"workspace delete": func() (cli.Command, error) {
   343  			return &command.WorkspaceDeleteCommand{
   344  				Meta: meta,
   345  			}, nil
   346  		},
   347  
   348  		//-----------------------------------------------------------
   349  		// Plumbing
   350  		//-----------------------------------------------------------
   351  
   352  		"force-unlock": func() (cli.Command, error) {
   353  			return &command.UnlockCommand{
   354  				Meta: meta,
   355  			}, nil
   356  		},
   357  
   358  		"state": func() (cli.Command, error) {
   359  			return &command.StateCommand{}, nil
   360  		},
   361  
   362  		"state list": func() (cli.Command, error) {
   363  			return &command.StateListCommand{
   364  				Meta: meta,
   365  			}, nil
   366  		},
   367  
   368  		"state rm": func() (cli.Command, error) {
   369  			return &command.StateRmCommand{
   370  				StateMeta: command.StateMeta{
   371  					Meta: meta,
   372  				},
   373  			}, nil
   374  		},
   375  
   376  		"state mv": func() (cli.Command, error) {
   377  			return &command.StateMvCommand{
   378  				StateMeta: command.StateMeta{
   379  					Meta: meta,
   380  				},
   381  			}, nil
   382  		},
   383  
   384  		"state pull": func() (cli.Command, error) {
   385  			return &command.StatePullCommand{
   386  				Meta: meta,
   387  			}, nil
   388  		},
   389  
   390  		"state push": func() (cli.Command, error) {
   391  			return &command.StatePushCommand{
   392  				Meta: meta,
   393  			}, nil
   394  		},
   395  
   396  		"state show": func() (cli.Command, error) {
   397  			return &command.StateShowCommand{
   398  				Meta: meta,
   399  			}, nil
   400  		},
   401  
   402  		"state replace-provider": func() (cli.Command, error) {
   403  			return &command.StateReplaceProviderCommand{
   404  				StateMeta: command.StateMeta{
   405  					Meta: meta,
   406  				},
   407  			}, nil
   408  		},
   409  	}
   410  
   411  	PrimaryCommands = []string{
   412  		"init",
   413  		"validate",
   414  		"plan",
   415  		"apply",
   416  		"destroy",
   417  	}
   418  
   419  	HiddenCommands = map[string]struct{}{
   420  		"env":             struct{}{},
   421  		"internal-plugin": struct{}{},
   422  		"push":            struct{}{},
   423  	}
   424  
   425  }
   426  
   427  // makeShutdownCh creates an interrupt listener and returns a channel.
   428  // A message will be sent on the channel for every interrupt received.
   429  func makeShutdownCh() <-chan struct{} {
   430  	resultCh := make(chan struct{})
   431  
   432  	signalCh := make(chan os.Signal, 4)
   433  	signal.Notify(signalCh, ignoreSignals...)
   434  	signal.Notify(signalCh, forwardSignals...)
   435  	go func() {
   436  		for {
   437  			<-signalCh
   438  			resultCh <- struct{}{}
   439  		}
   440  	}()
   441  
   442  	return resultCh
   443  }
   444  
   445  func credentialsSource(config *cliconfig.Config) (auth.CredentialsSource, error) {
   446  	helperPlugins := pluginDiscovery.FindPlugins("credentials", globalPluginDirs())
   447  	return config.CredentialsSource(helperPlugins)
   448  }