github.com/eliastor/durgaform@v0.0.0-20220816172711-d0ab2d17673e/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/eliastor/durgaform/internal/addrs"
    14  	"github.com/eliastor/durgaform/internal/command"
    15  	"github.com/eliastor/durgaform/internal/command/cliconfig"
    16  	"github.com/eliastor/durgaform/internal/command/views"
    17  	"github.com/eliastor/durgaform/internal/command/webbrowser"
    18  	"github.com/eliastor/durgaform/internal/getproviders"
    19  	pluginDiscovery "github.com/eliastor/durgaform/internal/plugin/discovery"
    20  	"github.com/eliastor/durgaform/internal/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 Durgaform is being run from a command prompt.
    26  const runningInAutomationEnvName = "TF_IN_AUTOMATION"
    27  
    28  // Commands is the mapping of all the available Durgaform 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  		ShutdownCh: makeShutdownCh(),
    99  
   100  		ProviderSource:       providerSrc,
   101  		ProviderDevOverrides: providerDevOverrides,
   102  		UnmanagedProviders:   unmanagedProviders,
   103  
   104  		AllowExperimentalFeatures: ExperimentsAllowed(),
   105  	}
   106  
   107  	// The command list is included in the durgaform -help
   108  	// output, which is in turn included in the docs at
   109  	// website/docs/cli/commands/index.html.markdown; if you
   110  	// add, remove or reclassify commands then consider updating
   111  	// that to match.
   112  
   113  	Commands = map[string]cli.CommandFactory{
   114  		"apply": func() (cli.Command, error) {
   115  			return &command.ApplyCommand{
   116  				Meta: meta,
   117  			}, nil
   118  		},
   119  
   120  		"console": func() (cli.Command, error) {
   121  			return &command.ConsoleCommand{
   122  				Meta: meta,
   123  			}, nil
   124  		},
   125  
   126  		"destroy": func() (cli.Command, error) {
   127  			return &command.ApplyCommand{
   128  				Meta:    meta,
   129  				Destroy: true,
   130  			}, nil
   131  		},
   132  
   133  		"env": func() (cli.Command, error) {
   134  			return &command.WorkspaceCommand{
   135  				Meta:       meta,
   136  				LegacyName: true,
   137  			}, nil
   138  		},
   139  
   140  		"env list": func() (cli.Command, error) {
   141  			return &command.WorkspaceListCommand{
   142  				Meta:       meta,
   143  				LegacyName: true,
   144  			}, nil
   145  		},
   146  
   147  		"env select": func() (cli.Command, error) {
   148  			return &command.WorkspaceSelectCommand{
   149  				Meta:       meta,
   150  				LegacyName: true,
   151  			}, nil
   152  		},
   153  
   154  		"env new": func() (cli.Command, error) {
   155  			return &command.WorkspaceNewCommand{
   156  				Meta:       meta,
   157  				LegacyName: true,
   158  			}, nil
   159  		},
   160  
   161  		"env delete": func() (cli.Command, error) {
   162  			return &command.WorkspaceDeleteCommand{
   163  				Meta:       meta,
   164  				LegacyName: true,
   165  			}, nil
   166  		},
   167  
   168  		"fmt": func() (cli.Command, error) {
   169  			return &command.FmtCommand{
   170  				Meta: meta,
   171  			}, nil
   172  		},
   173  
   174  		"get": func() (cli.Command, error) {
   175  			return &command.GetCommand{
   176  				Meta: meta,
   177  			}, nil
   178  		},
   179  
   180  		"graph": func() (cli.Command, error) {
   181  			return &command.GraphCommand{
   182  				Meta: meta,
   183  			}, nil
   184  		},
   185  
   186  		"import": func() (cli.Command, error) {
   187  			return &command.ImportCommand{
   188  				Meta: meta,
   189  			}, nil
   190  		},
   191  
   192  		"init": func() (cli.Command, error) {
   193  			return &command.InitCommand{
   194  				Meta: meta,
   195  			}, nil
   196  		},
   197  
   198  		"login": func() (cli.Command, error) {
   199  			return &command.LoginCommand{
   200  				Meta: meta,
   201  			}, nil
   202  		},
   203  
   204  		"logout": func() (cli.Command, error) {
   205  			return &command.LogoutCommand{
   206  				Meta: meta,
   207  			}, nil
   208  		},
   209  
   210  		"output": func() (cli.Command, error) {
   211  			return &command.OutputCommand{
   212  				Meta: meta,
   213  			}, nil
   214  		},
   215  
   216  		"plan": func() (cli.Command, error) {
   217  			return &command.PlanCommand{
   218  				Meta: meta,
   219  			}, nil
   220  		},
   221  
   222  		"providers": func() (cli.Command, error) {
   223  			return &command.ProvidersCommand{
   224  				Meta: meta,
   225  			}, nil
   226  		},
   227  
   228  		"providers lock": func() (cli.Command, error) {
   229  			return &command.ProvidersLockCommand{
   230  				Meta: meta,
   231  			}, nil
   232  		},
   233  
   234  		"providers mirror": func() (cli.Command, error) {
   235  			return &command.ProvidersMirrorCommand{
   236  				Meta: meta,
   237  			}, nil
   238  		},
   239  
   240  		"providers schema": func() (cli.Command, error) {
   241  			return &command.ProvidersSchemaCommand{
   242  				Meta: meta,
   243  			}, nil
   244  		},
   245  
   246  		"push": func() (cli.Command, error) {
   247  			return &command.PushCommand{
   248  				Meta: meta,
   249  			}, nil
   250  		},
   251  
   252  		"refresh": func() (cli.Command, error) {
   253  			return &command.RefreshCommand{
   254  				Meta: meta,
   255  			}, nil
   256  		},
   257  
   258  		"show": func() (cli.Command, error) {
   259  			return &command.ShowCommand{
   260  				Meta: meta,
   261  			}, nil
   262  		},
   263  
   264  		"taint": func() (cli.Command, error) {
   265  			return &command.TaintCommand{
   266  				Meta: meta,
   267  			}, nil
   268  		},
   269  
   270  		"test": func() (cli.Command, error) {
   271  			return &command.TestCommand{
   272  				Meta: meta,
   273  			}, nil
   274  		},
   275  
   276  		"validate": func() (cli.Command, error) {
   277  			return &command.ValidateCommand{
   278  				Meta: meta,
   279  			}, nil
   280  		},
   281  
   282  		"version": func() (cli.Command, error) {
   283  			return &command.VersionCommand{
   284  				Meta:              meta,
   285  				Version:           Version,
   286  				VersionPrerelease: VersionPrerelease,
   287  				Platform:          getproviders.CurrentPlatform,
   288  				CheckFunc:         commandVersionCheck,
   289  			}, nil
   290  		},
   291  
   292  		"untaint": func() (cli.Command, error) {
   293  			return &command.UntaintCommand{
   294  				Meta: meta,
   295  			}, nil
   296  		},
   297  
   298  		"workspace": func() (cli.Command, error) {
   299  			return &command.WorkspaceCommand{
   300  				Meta: meta,
   301  			}, nil
   302  		},
   303  
   304  		"workspace list": func() (cli.Command, error) {
   305  			return &command.WorkspaceListCommand{
   306  				Meta: meta,
   307  			}, nil
   308  		},
   309  
   310  		"workspace select": func() (cli.Command, error) {
   311  			return &command.WorkspaceSelectCommand{
   312  				Meta: meta,
   313  			}, nil
   314  		},
   315  
   316  		"workspace show": func() (cli.Command, error) {
   317  			return &command.WorkspaceShowCommand{
   318  				Meta: meta,
   319  			}, nil
   320  		},
   321  
   322  		"workspace new": func() (cli.Command, error) {
   323  			return &command.WorkspaceNewCommand{
   324  				Meta: meta,
   325  			}, nil
   326  		},
   327  
   328  		"workspace delete": func() (cli.Command, error) {
   329  			return &command.WorkspaceDeleteCommand{
   330  				Meta: meta,
   331  			}, nil
   332  		},
   333  
   334  		//-----------------------------------------------------------
   335  		// Plumbing
   336  		//-----------------------------------------------------------
   337  
   338  		"force-unlock": func() (cli.Command, error) {
   339  			return &command.UnlockCommand{
   340  				Meta: meta,
   341  			}, nil
   342  		},
   343  
   344  		"state": func() (cli.Command, error) {
   345  			return &command.StateCommand{}, nil
   346  		},
   347  
   348  		"state list": func() (cli.Command, error) {
   349  			return &command.StateListCommand{
   350  				Meta: meta,
   351  			}, nil
   352  		},
   353  
   354  		"state rm": func() (cli.Command, error) {
   355  			return &command.StateRmCommand{
   356  				StateMeta: command.StateMeta{
   357  					Meta: meta,
   358  				},
   359  			}, nil
   360  		},
   361  
   362  		"state mv": func() (cli.Command, error) {
   363  			return &command.StateMvCommand{
   364  				StateMeta: command.StateMeta{
   365  					Meta: meta,
   366  				},
   367  			}, nil
   368  		},
   369  
   370  		"state pull": func() (cli.Command, error) {
   371  			return &command.StatePullCommand{
   372  				Meta: meta,
   373  			}, nil
   374  		},
   375  
   376  		"state push": func() (cli.Command, error) {
   377  			return &command.StatePushCommand{
   378  				Meta: meta,
   379  			}, nil
   380  		},
   381  
   382  		"state show": func() (cli.Command, error) {
   383  			return &command.StateShowCommand{
   384  				Meta: meta,
   385  			}, nil
   386  		},
   387  
   388  		"state replace-provider": func() (cli.Command, error) {
   389  			return &command.StateReplaceProviderCommand{
   390  				StateMeta: command.StateMeta{
   391  					Meta: meta,
   392  				},
   393  			}, nil
   394  		},
   395  	}
   396  
   397  	PrimaryCommands = []string{
   398  		"init",
   399  		"validate",
   400  		"plan",
   401  		"apply",
   402  		"destroy",
   403  	}
   404  
   405  	HiddenCommands = map[string]struct{}{
   406  		"env":             struct{}{},
   407  		"internal-plugin": struct{}{},
   408  		"push":            struct{}{},
   409  	}
   410  
   411  }
   412  
   413  // makeShutdownCh creates an interrupt listener and returns a channel.
   414  // A message will be sent on the channel for every interrupt received.
   415  func makeShutdownCh() <-chan struct{} {
   416  	resultCh := make(chan struct{})
   417  
   418  	signalCh := make(chan os.Signal, 4)
   419  	signal.Notify(signalCh, ignoreSignals...)
   420  	signal.Notify(signalCh, forwardSignals...)
   421  	go func() {
   422  		for {
   423  			<-signalCh
   424  			resultCh <- struct{}{}
   425  		}
   426  	}()
   427  
   428  	return resultCh
   429  }
   430  
   431  func credentialsSource(config *cliconfig.Config) (auth.CredentialsSource, error) {
   432  	helperPlugins := pluginDiscovery.FindPlugins("credentials", globalPluginDirs())
   433  	return config.CredentialsSource(helperPlugins)
   434  }