2

I am using Cobra to make some cli updated to my app. I want to make this command required, meaning the application should fail if it doesn't find the argument it is looking for.

package commands

import (
    "github.com/spf13/cobra"
    "errors"
    "fmt"
)

var (
    Env string
)

var RootCmd = &cobra.Command{
    Use:   "myapp",
    Short: "tool",
    Long:  `tool`,
    Run: func(cmd *cobra.Command, args []string)  {
        // Root command does nothing
    },
}

func init() {
    RootCmd.AddCommand(Environment)
}

var Environment = &cobra.Command{
    Use:   "env",
    Short: "Specify Environment to run against",
    Long: `Can be dev or prod`,
    Args: func(cmd *cobra.Command, args []string) error {
        if len(args) != 1 {
            return errors.New("requires at least one arg")
        }

        if args[0] == "dev" || args[0] == "prod" {
            return nil
        }else {
            return errors.New("input can only be dev or prod")
        }
        return fmt.Errorf("invalid env specified: %s", args[0])
    },
    PreRunE: func(cmd *cobra.Command, args []string) error {
        if len(args) != 1 {
          return fmt.Errorf("env is required")
        }
      return nil
    },
    Run: func(cmd *cobra.Command, args []string) {
        Env = args[0]
    },
}

and main package is

package main

import (
    "fmt"
    "log"
    "os"
    "util"
    "commands"
)

func main() {
    log.Println("Executing")

    if err := commands.RootCmd.Execute(); err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
    log.Println("Executing")
}

Now if I run this as ./myApp without any env, it doesn't complain about it. However if I use env after myapp then it activates the function and runs all the validations.

Adrian
  • 42,911
  • 6
  • 107
  • 99
wayfare
  • 1,802
  • 5
  • 20
  • 37
  • 2
    you could remove 'Run' section from the RootCmd so that it displays the list of available subcommands and exit. It works more or less like a complaint with safer exit. – codenio Feb 17 '18 at 07:19

2 Answers2

4

Omitting the Run (and RunE) field from the cobra.Command will make it a requirement for a valid subcommand to be given:

var RootCmd = &cobra.Command{
    Use:   "myapp",
    Short: "tool",
    Long:  `tool long help...`,
}

If no subcommand is given on the command line, Cobra will print out the command's Help() text , which will include the root command's Long help text and the autogenerated usage help for all subcommands.

hampercm
  • 161
  • 1
  • 4
1

You can just make the body of the function handle it, perhaps by printing help and exiting as non-successful:

Run: func(cmd *cobra.Command, args []string)  {
    // Root command does nothing
    cmd.Help()
    os.Exit(1)
},
Adrian
  • 42,911
  • 6
  • 107
  • 99
  • Thanks for replying @Adrian.I thought of doing it, but wondering if there is some flag or better way to do it. In future there will be many flags and it will look ugly to have all of them in run body. – wayfare Nov 13 '17 at 19:54
  • I'm not sure what you mean... there are no flags used in your quoted code, and the above would only need to be used once, in one place (`RootCmd.Run`) regardless of how many subcommands you have. – Adrian Nov 13 '17 at 20:00