Exemplo n.º 1
0
func main() {
	parser := args.NewParser(args.Name("http-client"),
		args.Desc("Example http client client"))

	parser.AddOption("--verbose").Alias("-v").Count().
		Help("Be verbose")
	parser.AddOption("--endpoint").Default("http://localhost:1234").Env("API_ENDPOINT").
		Help("The HTTP endpoint our client will talk too")

	parser.AddCommand("super-chickens", func(subParser *args.ArgParser, data interface{}) int {
		subParser.AddCommand("create", createChickens)
		subParser.AddCommand("list", listChickens)
		subParser.AddCommand("delete", deleteChickens)

		// Apply our super metadata =)
		shared := data.(*SharedStruct)
		shared.Metadata = "super"

		// Run the sub-commands
		retCode, err := subParser.ParseAndRun(nil, data)
		if err != nil {
			fmt.Println(err.Error())
			return 1
		}
		return retCode
	})

	// Add our non super chicken actions
	parser.AddCommand("create", createChickens)
	parser.AddCommand("list", listChickens)
	parser.AddCommand("delete", deleteChickens)

	// Parse the command line
	opts, err := parser.ParseArgs(nil)
	if err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
		os.Exit(1)
	}

	// Build our url from what the user passed in
	parts, err := url.Parse(opts.String("endpoint"))
	if err != nil {
		fmt.Fprint(os.Stderr, "url endpoint '%s' is invalid", opts.String("endpoint"), err.Error())
		os.Exit(1)
	}
	// This is a shows how you can pass in arbitrary struct
	// data to your sub-commands allows you to share data and resources
	// with sub-commands with out resorting to global variables
	super := &SharedStruct{Metadata: "", Url: parts}

	// Run the command chosen by the user
	retCode, err := parser.RunCommand(super)
	if err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
		os.Exit(1)
	}
	os.Exit(retCode)
}
Exemplo n.º 2
0
func main() {
	var conf Config

	// Create the parser with program name 'example'
	// and environment variables prefixed with APP_
	parser := args.NewParser(args.Name("demo"), args.EnvPrefix("APP_"),
		args.Desc("This is a demo app to showcase some features of args"))

	// Store Integers directly into a struct with a default value
	parser.AddOption("--power-level").Alias("-p").StoreInt(&conf.PowerLevel).
		Env("POWER_LEVEL").Default("10000").Help("set our power level")

	// Command line options can begin with -name, --name or even ++name
	// Most non word characters are supported
	parser.AddOption("++config-file").Alias("+c").IsString().
		Default("/path/to/config").Help("path to config file")

	// Use the args.Env() function to define an environment variable
	// NOTE: Since the parser was passed args.EnvPrefix("APP_") the actual
	// environment variable name is 'APP_MESSAGE'
	parser.AddOption("--message").Alias("-m").StoreStr(&conf.Message).
		Env("MESSAGE").Default("over-ten-thousand").Help("send a message")

	// Pass a comma separated list of strings and get a []string slice
	parser.AddOption("--slice").Alias("-s").StoreStringSlice(&conf.StringSlice).Env("LIST").
		Default("one,two,three").Help("list of messages")

	// Count the number of times an option is seen
	parser.AddOption("--verbose").Alias("-v").Count().StoreInt(&conf.Verbose).Help("be verbose")

	// Set bool to true if the option is present on the command line
	parser.AddOption("--debug").Alias("-d").IsTrue().Help("turn on Debug")

	// Specify the type of the arg with IsInt(), IsString(), IsBool() or IsTrue()
	parser.AddOption("--help").Alias("-h").IsTrue().Help("show this help message")

	// Add Required arguments
	parser.AddArgument("the-question").Required().
		StoreStr(&conf.TheQuestion).Help("Before you have an answer")

	// Add Optional arguments
	parser.AddArgument("the-answer").IsInt().Default("42").
		StoreInt(&conf.TheAnswer).Help("It must be 42")

	// 'Conf' options are not set via the command line but can be set
	// via a config file or an environment variable
	parser.AddConfig("twelve-factor").Env("TWELVE_FACTOR").Help("Demo of config options")

	// Define a 'database' subgroup
	db := parser.InGroup("database")

	// Add command line options to the subgroup
	db.AddOption("--host").Alias("-dH").StoreStr(&conf.DbHost).
		Default("localhost").Help("database hostname")

	// Add subgroup specific config. 'Conf' options are not set via the
	// command line but can be set via a config file or anything that calls parser.Apply()
	db.AddConfig("debug").IsTrue().Help("enable database debug")

	// 'Conf' option names are not allowed to start with a non word character like
	// '--' or '++' so they can not be confused with command line options
	db.AddConfig("database").IsString().Default("myDatabase").Help("name of database to use")

	// If no type is specified, defaults to 'IsString'
	db.AddConfig("user").Help("database user")
	db.AddConfig("pass").Help("database password")

	// Pass our own argument list, or nil to parse os.Args[]
	opt := parser.ParseArgsSimple(nil)

	// NOTE: ParseArgsSimple() is just a convenience, you can call
	// parser.ParseArgs(nil) directly and handle the errors
	// yourself if you have more complicated use case

	// Demo default variables in a struct
	fmt.Printf("Power        '%d'\n", conf.PowerLevel)
	fmt.Printf("Message      '%s'\n", conf.Message)
	fmt.Printf("String Slice '%s'\n", conf.StringSlice)
	fmt.Printf("DbHost       '%s'\n", conf.DbHost)
	fmt.Printf("TheAnswer    '%d'\n", conf.TheAnswer)
	fmt.Println("")

	// If user asked for --help or there were no options
	// passed and none where required
	if opt.NoArgs() || opt.Bool("help") {
		parser.PrintHelp()
		os.Exit(-1)
	}

	fmt.Println("")
	fmt.Println("==================")
	fmt.Println(" Direct Cast")
	fmt.Println("==================")

	// Fetch values by using the Cast functions
	fmt.Printf("Power               '%d'\n", opt.Int("power-level"))
	fmt.Printf("Message             '%s'\n", opt.String("message"))
	fmt.Printf("String Slice        '%s'\n", opt.StringSlice("slice"))
	fmt.Printf("Verbose             '%d'\n", opt.Int("verbose"))
	fmt.Printf("Debug               '%t'\n", opt.Bool("debug"))
	fmt.Printf("TheAnswer           '%d'\n", opt.Int("the-answer"))
	fmt.Printf("TheAnswer as String '%s'\n", opt.String("the-answer"))

	fmt.Println("")
	fmt.Println("==================")
	fmt.Println(" Database Group")
	fmt.Println("==================")

	// Fetch Group values
	dbAddOption := opt.Group("database")
	fmt.Printf("CAST DB Host   '%s'\n", dbAddOption.String("host"))
	fmt.Printf("CAST DB Debug  '%t'\n", dbAddOption.Bool("debug"))
	fmt.Printf("CAST DB User   '%s'\n", dbAddOption.String("user"))
	fmt.Printf("CAST DB Pass   '%s'\n", dbAddOption.String("pass"))

	fmt.Println("")

	iniFile := []byte(`
		power-level=20000
		message=OVER-TEN-THOUSAND!
		slice=three,four,five,six
		verbose=5
		debug=true

		[database]
		debug=false
		host=mysql.thrawn01.org
		user=my-username
		pass=my-password
	`)

	// Make configuration simple by reading arguments from an INI file
	opts, err := parser.FromINI(iniFile)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(-1)
	}

	fmt.Println("")
	fmt.Println("==================")
	fmt.Println("From INI file")
	fmt.Println("==================")

	// Values from the config file are used only if the argument is not present
	// on the commandline
	fmt.Printf("INI Power      '%d'\n", conf.PowerLevel)
	fmt.Printf("INI Message    '%s'\n", conf.Message)
	fmt.Printf("INI Slice      '%s'\n", conf.StringSlice)
	fmt.Printf("INI Verbose    '%d'\n", conf.Verbose)
	fmt.Printf("INI Debug      '%t'\n", opts.Bool("debug"))
	fmt.Println("")

	// Create an Options object from a map
	opts = parser.NewOptionsFromMap(
		map[string]interface{}{
			"int":    1,
			"bool":   true,
			"string": "one",
			"endpoints": map[string]interface{}{
				"endpoint1": "host1",
				"endpoint2": "host2",
				"endpoint3": "host3",
			},
			"deeply": map[string]interface{}{
				"nested": map[string]interface{}{
					"thing": "foo",
				},
				"foo": "bar",
			},
		},
	)

	// Small demo of how Group() works with options
	opts.String("string")                       // == "one"
	opts.Group("endpoints")                     // == *args.Options
	opts.Group("endpoints").String("endpoint1") // == "host1"
	opts.Group("endpoints").ToMap()             // map[string]interface{} {"endpoint1": "host1", ...}
	opts.StringMap("endpoints")                 // map[string]string {"endpoint1": "host1", ...}
	opts.KeySlice("endpoints")                  // [ "endpoint1", "endpoint2", ]
	opts.StringSlice("endpoints")               // [ "host1", "host2", "host3" ]

	// Leaves the door open for IntSlice(), IntMap(), etc....
}
Exemplo n.º 3
0
package args_test

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/thrawn01/args"
)

var _ = Describe("Options", func() {
	var opts *args.Options
	var log *TestLogger
	BeforeEach(func() {
		log = NewTestLogger()
		parser := args.NewParser()
		parser.SetLog(log)

		opts = parser.NewOptionsFromMap(
			map[string]interface{}{
				"int":    1,
				"bool":   true,
				"string": "one",
				"endpoints": map[string]interface{}{
					"endpoint1": "host1",
					"endpoint2": "host2",
					"endpoint3": "host3",
				},
				"deeply": map[string]interface{}{
					"nested": map[string]interface{}{
						"thing": "foo",
					},
					"foo": "bar",
Exemplo n.º 4
0
func main() {

	parser := args.NewParser(args.Name("watch"))
	parser.AddOption("--bind").Alias("-b").Default("localhost:8080").
		Help("Interface to bind the server too")
	parser.AddOption("--complex-example").Alias("-ce").IsBool().
		Help("Run the more complex example")
	parser.AddOption("--config-file").Alias("-c").
		Help("The Config file to load and watch our config from")

	// Add a connection string to the database group
	parser.AddOption("--connection-string").InGroup("database").Alias("-cS").
		Default("mysql://username@hostname:MyDB").
		Help("Connection string used to connect to the database")

	// Store the password in the config and not passed via the command line
	parser.AddConfig("password").InGroup("database").Help("database password")
	// Specify a config file version, when this version number is updated, the user is signaling to the application
	// that all edits are complete and the application can reload the config
	parser.AddConfig("version").IsInt().Default("0").Help("config file version")

	appConf, err := parser.ParseArgs(nil)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(-1)
	}

	// Simple handler that prints out our config information
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		conf := appConf.GetOpts()

		db := conf.Group("database")
		payload, err := json.Marshal(map[string]string{
			"bind":     conf.String("bind"),
			"mysql":    db.String("connection-string"),
			"password": conf.Group("database").String("password"),
		})
		if err != nil {
			fmt.Println("error:", err)
		}
		w.Header().Set("Content-Type", "application/json")
		w.Write(payload)
	})

	var cancelWatch args.WatchCancelFunc
	if appConf.Bool("complex-example") {
		cancelWatch = complex(parser)
	} else {
		cancelWatch = simple(parser)
	}

	// Shut down the watcher when done
	defer cancelWatch()

	// Listen and serve requests
	log.Printf("Listening for requests on %s", appConf.String("bind"))
	err = http.ListenAndServe(appConf.String("bind"), nil)
	if err != nil {
		log.Println(err)
		os.Exit(-1)
	}
}
Exemplo n.º 5
0
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/thrawn01/args"
)

var _ = Describe("ArgParser", func() {
	var log *TestLogger

	BeforeEach(func() {
		log = NewTestLogger()
	})

	Describe("ArgParser.ParseArgs(nil)", func() {
		It("Should return error if AddOption() was never called", func() {
			parser := args.NewParser(args.NoHelp())
			_, err := parser.ParseArgs(nil)
			Expect(err).ToNot(BeNil())
			Expect(err.Error()).To(Equal("Must create some options to match with args.AddOption() before calling arg.ParseArgs()"))
		})
		It("Should add Help option if none provided", func() {
			parser := args.NewParser()
			_, err := parser.ParseArgs(nil)
			Expect(err).To(BeNil())
			rule := parser.GetRules()[0]
			Expect(rule.Name).To(Equal("help"))
		})
	})
	Describe("ArgParser.AddOption()", func() {
		cmdLine := []string{"--one", "-two", "++three", "+four", "--power-level"}