github.com/ActiveState/cli@v0.0.0-20240508170324-6801f60cd051/cmd/state/internal/cmdtree/cmdtree.go (about)

     1  package cmdtree
     2  
     3  import (
     4  	"time"
     5  
     6  	"github.com/ActiveState/cli/cmd/state/internal/cmdtree/exechandlers/cmdcall"
     7  	"github.com/ActiveState/cli/internal/captain"
     8  	"github.com/ActiveState/cli/internal/condition"
     9  	"github.com/ActiveState/cli/internal/locale"
    10  	"github.com/ActiveState/cli/internal/logging"
    11  	"github.com/ActiveState/cli/internal/primer"
    12  	"github.com/ActiveState/cli/internal/profile"
    13  	"github.com/ActiveState/cli/internal/runners/state"
    14  	secretsapi "github.com/ActiveState/cli/pkg/platform/api/secrets"
    15  )
    16  
    17  // CmdTree manages a tree of captain.Command instances.
    18  type CmdTree struct {
    19  	cmd *captain.Command
    20  }
    21  
    22  // New prepares a CmdTree.
    23  func New(prime *primer.Values, args ...string) *CmdTree {
    24  	defer profile.Measure("cmdtree:New", time.Now())
    25  
    26  	globals := newGlobalOptions()
    27  
    28  	authCmd := newAuthCommand(prime, globals)
    29  	authCmd.AddChildren(
    30  		newSignupCommand(prime),
    31  		newLogoutCommand(prime),
    32  	)
    33  
    34  	cveCmd := newCveCommand(prime)
    35  	cveCmd.AddChildren(
    36  		newReportCommand(prime),
    37  		newOpenCommand(prime),
    38  	)
    39  
    40  	exportCmd := newExportCommand(prime)
    41  	exportCmd.AddChildren(
    42  		newJWTCommand(prime),
    43  		newPrivateKeyCommand(prime),
    44  		newAPIKeyCommand(prime),
    45  		newExportConfigCommand(prime),
    46  		newExportGithubActionCommand(prime),
    47  		newExportDocsCommand(prime),
    48  		newExportEnvCommand(prime),
    49  		newLogCommand(prime),
    50  	)
    51  
    52  	platformsCmd := newPlatformsCommand(prime)
    53  	platformsCmd.AddChildren(
    54  		newPlatformsSearchCommand(prime),
    55  		newPlatformsAddCommand(prime),
    56  		newPlatformsRemoveCommand(prime),
    57  	)
    58  
    59  	scriptsCmd := newScriptsCommand(prime)
    60  	scriptsCmd.AddChildren(
    61  		newScriptsEditCommand(prime),
    62  	)
    63  
    64  	languagesCmd := newLanguagesCommand(prime)
    65  	languagesCmd.AddChildren(
    66  		newLanguageInstallCommand(prime),
    67  		newLanguageSearchCommand(prime),
    68  	)
    69  
    70  	cleanCmd := newCleanCommand(prime)
    71  	cleanCmd.AddChildren(
    72  		newCleanUninstallCommand(prime, globals),
    73  		newCleanCacheCommand(prime, globals),
    74  		newCleanConfigCommand(prime),
    75  	)
    76  
    77  	deployCmd := newDeployCommand(prime)
    78  	deployCmd.AddChildren(
    79  		newDeployInstallCommand(prime),
    80  		newDeployConfigureCommand(prime),
    81  		newDeploySymlinkCommand(prime),
    82  		newDeployReportCommand(prime),
    83  		newDeployUninstallCommand(prime),
    84  	)
    85  
    86  	tutorialCmd := newTutorialCommand(prime)
    87  	tutorialCmd.AddChildren(newTutorialProjectCommand(prime))
    88  
    89  	eventsCmd := newEventsCommand(prime)
    90  	eventsCmd.AddChildren(newEventsLogCommand(prime))
    91  
    92  	installCmd := newInstallCommand(prime)
    93  	uninstallCmd := newUninstallCommand(prime)
    94  	importCmd := newImportCommand(prime, globals)
    95  	searchCmd := newSearchCommand(prime)
    96  	infoCmd := newInfoCommand(prime)
    97  
    98  	pkgsCmd := newPackagesCommand(prime)
    99  	addAs := addCmdAs{
   100  		pkgsCmd,
   101  		prime,
   102  	}
   103  	addAs.deprecatedAlias(installCmd, "add")
   104  	addAs.deprecatedAlias(installCmd, "update")
   105  	addAs.deprecatedAlias(uninstallCmd, "remove")
   106  	addAs.deprecatedAlias(importCmd, "import")
   107  	addAs.deprecatedAlias(searchCmd, "search")
   108  
   109  	bundlesCmd := newBundlesCommand(prime)
   110  	bundlesCmd.AddChildren(
   111  		newBundleInstallCommand(prime),
   112  		newBundleUninstallCommand(prime),
   113  		newBundlesSearchCommand(prime),
   114  	)
   115  
   116  	secretsClient := secretsapi.InitializeClient(prime.Auth())
   117  	secretsCmd := newSecretsCommand(secretsClient, prime)
   118  	secretsCmd.AddChildren(
   119  		newSecretsGetCommand(prime),
   120  		newSecretsSetCommand(prime),
   121  		newSecretsSyncCommand(secretsClient, prime),
   122  	)
   123  
   124  	projectsCmd := newProjectsCommand(prime)
   125  	projectsCmd.AddChildren(
   126  		newRemoteProjectsCommand(prime),
   127  		newProjectsEditCommand(prime),
   128  		newDeleteProjectsCommand(prime),
   129  		newMoveProjectsCommand(prime),
   130  	)
   131  
   132  	updateCmd := newUpdateCommand(prime)
   133  	updateCmd.AddChildren(
   134  		newUpdateLockCommand(prime, globals),
   135  		newUpdateUnlockCommand(prime, globals))
   136  
   137  	branchCmd := newBranchCommand(prime)
   138  	branchCmd.AddChildren(
   139  		/*  Disabled as per https://www.pivotaltracker.com/story/show/177051006
   140  		newBranchAddCommand(prime),
   141  		*/
   142  		newBranchSwitchCommand(prime),
   143  	)
   144  	prepareCmd := newPrepareCommand(prime)
   145  	prepareCmd.AddChildren(newPrepareCompletionsCommand(prime))
   146  
   147  	configCmd := newConfigCommand(prime)
   148  	configCmd.AddChildren(newConfigGetCommand(prime), newConfigSetCommand(prime))
   149  
   150  	checkoutCmd := newCheckoutCommand(prime)
   151  
   152  	useCmd := newUseCommand(prime)
   153  	useCmd.AddChildren(
   154  		newUseResetCommand(prime, globals),
   155  		newUseShowCommand(prime),
   156  	)
   157  
   158  	shellCmd := newShellCommand(prime)
   159  
   160  	refreshCmd := newRefreshCommand(prime)
   161  
   162  	artifactsCmd := newArtifactsCommand(prime)
   163  	artifactsCmd.AddChildren(
   164  		newArtifactsDownloadCommand(prime),
   165  	)
   166  
   167  	stateCmd := newStateCommand(globals, prime)
   168  	stateCmd.AddChildren(
   169  		newHelloCommand(prime),
   170  		newActivateCommand(prime),
   171  		newInitCommand(prime),
   172  		newPushCommand(prime),
   173  		cveCmd,
   174  		projectsCmd,
   175  		authCmd,
   176  		exportCmd,
   177  		newOrganizationsCommand(prime),
   178  		newRunCommand(prime),
   179  		newShowCommand(prime),
   180  		installCmd,
   181  		uninstallCmd,
   182  		importCmd,
   183  		searchCmd,
   184  		infoCmd,
   185  		pkgsCmd,
   186  		bundlesCmd,
   187  		platformsCmd,
   188  		newHistoryCommand(prime),
   189  		cleanCmd,
   190  		languagesCmd,
   191  		deployCmd,
   192  		scriptsCmd,
   193  		eventsCmd,
   194  		newPullCommand(prime, globals),
   195  		updateCmd,
   196  		newForkCommand(prime),
   197  		newPpmCommand(prime),
   198  		newInviteCommand(prime),
   199  		tutorialCmd,
   200  		prepareCmd,
   201  		newProtocolCommand(prime),
   202  		newExecCommand(prime, args...),
   203  		newRevertCommand(prime, globals),
   204  		newResetCommand(prime, globals),
   205  		secretsCmd,
   206  		branchCmd,
   207  		newLearnCommand(prime),
   208  		configCmd,
   209  		checkoutCmd,
   210  		useCmd,
   211  		shellCmd,
   212  		refreshCmd,
   213  		newSwitchCommand(prime),
   214  		newTestCommand(prime),
   215  		newCommitCommand(prime),
   216  		newPublish(prime),
   217  		newEvalCommand(prime),
   218  		newManifestCommmand(prime),
   219  		artifactsCmd,
   220  	)
   221  
   222  	return &CmdTree{
   223  		cmd: stateCmd,
   224  	}
   225  }
   226  
   227  type globalOptions struct {
   228  	Verbose        bool
   229  	Output         string
   230  	Monochrome     bool
   231  	NonInteractive bool
   232  }
   233  
   234  // Group instances are used to group command help output.
   235  var (
   236  	EnvironmentSetupGroup = captain.NewCommandGroup(locale.Tl("group_environment_setup", "Environment Setup"), 10)
   237  	EnvironmentUsageGroup = captain.NewCommandGroup(locale.Tl("group_environment_usage", "Environment Usage"), 9)
   238  	ProjectUsageGroup     = captain.NewCommandGroup(locale.Tl("group_project_usages", "Project Usage"), 8)
   239  	PackagesGroup         = captain.NewCommandGroup(locale.Tl("group_packages", "Package Management"), 7)
   240  	PlatformGroup         = captain.NewCommandGroup(locale.Tl("group_tools", "Platform"), 6)
   241  	VCSGroup              = captain.NewCommandGroup(locale.Tl("group_vcs", "Version Control"), 5)
   242  	AutomationGroup       = captain.NewCommandGroup(locale.Tl("group_automation", "Automation"), 4)
   243  	UtilsGroup            = captain.NewCommandGroup(locale.Tl("group_utils", "Utilities"), 3)
   244  	AuthorGroup           = captain.NewCommandGroup(locale.Tl("group_author", "Author"), 6)
   245  )
   246  
   247  func newGlobalOptions() *globalOptions {
   248  	return &globalOptions{}
   249  }
   250  
   251  func newStateCommand(globals *globalOptions, prime *primer.Values) *captain.Command {
   252  	opts := state.NewOptions()
   253  	var help bool
   254  
   255  	runner := state.New(opts, prime)
   256  	cmd := captain.NewCommand(
   257  		"state",
   258  		"",
   259  		locale.T("state_description"),
   260  		prime,
   261  		[]*captain.Flag{
   262  			{
   263  				Name:        "locale",
   264  				Shorthand:   "l",
   265  				Description: locale.T("flag_state_locale_description"),
   266  				Persist:     true,
   267  				Value:       &opts.Locale,
   268  			},
   269  			{
   270  				Name:        "verbose",
   271  				Shorthand:   "v",
   272  				Description: locale.T("flag_state_verbose_description"),
   273  				Persist:     true,
   274  				OnUse: func() {
   275  					if !condition.InUnitTest() {
   276  						logging.CurrentHandler().SetVerbose(true)
   277  					}
   278  				},
   279  				Value: &globals.Verbose,
   280  			},
   281  			{
   282  				Name:        "mono", // Name and Shorthand should be kept in sync with cmd/state/output.go
   283  				Persist:     true,
   284  				Description: locale.T("flag_state_monochrome_output_description"),
   285  				Value:       &globals.Monochrome,
   286  			},
   287  			{
   288  				Name:        "output", // Name and Shorthand should be kept in sync with cmd/state/output.go
   289  				Shorthand:   "o",
   290  				Description: locale.T("flag_state_output_description"),
   291  				Persist:     true,
   292  				Value:       &globals.Output,
   293  			},
   294  			{
   295  				Name:        "non-interactive", // Name and Shorthand should be kept in sync with cmd/state/output.go
   296  				Description: locale.T("flag_state_non_interactive_description"),
   297  				Shorthand:   "n",
   298  				Persist:     true,
   299  				Value:       &globals.NonInteractive,
   300  			},
   301  			{
   302  				Name:        "version",
   303  				Description: locale.T("flag_state_version_description"),
   304  				Value:       &opts.Version,
   305  			},
   306  			{
   307  				Name:        "help",
   308  				Description: locale.Tl("flag_help", "Help for this command"),
   309  				Shorthand:   "h",
   310  				Persist:     true,
   311  				Value:       &help, // need to store the value somewhere, but Cobra handles this flag by itself
   312  			},
   313  		},
   314  		[]*captain.Argument{},
   315  		func(ccmd *captain.Command, args []string) error {
   316  			if globals.Verbose {
   317  				logging.CurrentHandler().SetVerbose(true)
   318  			}
   319  
   320  			return runner.Run(ccmd.Usage)
   321  		},
   322  	)
   323  
   324  	cmdCall := cmdcall.New(prime)
   325  
   326  	cmd.SetHasVariableArguments()
   327  	cmd.OnExecStart(cmdCall.OnExecStart)
   328  	cmd.OnExecStop(cmdCall.OnExecStop)
   329  	cmd.SetSupportsStructuredOutput()
   330  
   331  	return cmd
   332  }
   333  
   334  // Execute runs the CmdTree using the provided CLI arguments.
   335  func (ct *CmdTree) Execute(args []string) error {
   336  	defer profile.Measure("cmdtree:Execute", time.Now())
   337  	return ct.cmd.Execute(args)
   338  }
   339  
   340  func (ct *CmdTree) OnExecStart(handler captain.ExecEventHandler) {
   341  	ct.cmd.OnExecStart(handler)
   342  }
   343  
   344  func (ct *CmdTree) OnExecStop(handler captain.ExecEventHandler) {
   345  	ct.cmd.OnExecStop(handler)
   346  }
   347  
   348  // Command returns the root command of the CmdTree
   349  func (ct *CmdTree) Command() *captain.Command {
   350  	return ct.cmd
   351  }
   352  
   353  type addCmdAs struct {
   354  	parent *captain.Command
   355  	prime  *primer.Values
   356  }
   357  
   358  func (a *addCmdAs) deprecatedAlias(aliased *captain.Command, name string) {
   359  	cmd := captain.NewCommand(
   360  		name,
   361  		aliased.Title(),
   362  		aliased.Description(),
   363  		a.prime,
   364  		aliased.Flags(),
   365  		aliased.Arguments(),
   366  		func(c *captain.Command, args []string) error {
   367  			msg := locale.Tl(
   368  				"cmd_deprecated_notice",
   369  				"This command is deprecated. Please use '[ACTIONABLE]state {{.V0}}[/RESET]' instead.",
   370  				aliased.Name(),
   371  			)
   372  
   373  			a.prime.Output().Notice(msg)
   374  
   375  			return aliased.ExecuteFunc()(c, args)
   376  		},
   377  	)
   378  
   379  	cmd.SetHidden(true)
   380  	cmd.SetHasVariableArguments()
   381  
   382  	a.parent.AddChildren(cmd)
   383  }