Example #1
0
// Show help.
// This command is useful for placing at the front of a CLI "subcommand" to have it output
// help information. It will only trigger when "show" is set to true, so another command
// can, for example, check for a "-h" or "-help" flag and set "show" based on that.
//
// Params:
// 	- show (bool): If `true`, show help.
// 	- summary (string): A one-line summary of the command.
// 	- description (string): A short description of what the command does.
// 	- usage (string): usage information.
// 	- flags (FlagSet): Flags that are supported. The FlagSet will be converted to help text.
// 	- writer (Writer): The location that this will write to. Default is os.Stdout
// 	- subcommands ([]string): A list of subcommands. This will be formatted as help text.
func ShowHelp(cxt cookoo.Context, params *cookoo.Params) (interface{}, cookoo.Interrupt) {
	showHelp := false
	showHelpO := params.Get("show", false)
	switch showHelpO.(type) {
	case string:
		showHelp = strings.ToLower(showHelpO.(string)) == "true"
	case bool:
		showHelp = showHelpO.(bool)
	}

	writer := params.Get("writer", os.Stdout).(io.Writer)

	pmap := params.AsMap()

	// Last resort: If no summary, pull it from the route description.
	if summary, ok := pmap["summary"]; !ok || len(summary.(string)) == 0 {
		pmap["summary"] = cxt.Get("route.Description", "").(string)
	}

	sections := []string{"summary", "description", "usage"}
	if _, ok := params.Has("subcommands"); ok {
		sections = append(sections, "subcommands")
	}

	if showHelp {
		displayHelp(sections, pmap, writer)
		return true, new(cookoo.Stop)
	}

	return false, nil
}
Example #2
0
// Template is a template-based text formatter.
//
// This uses the core `text/template` to process a given string template.
//
// Params
// 	- template (string): A template string.
// 	- template.Context (bool): If true, the context will be placed into the
// 		template renderer as 'Cxt', and can be used as `{{.Cxt.Foo}}`. False
// 		by default.
// 	- ... (interface{}): Values passed into the template.
//
// Conventionally, template variables should start with an initial capital.
//
// Returns a formatted string.
func Template(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	format := cookoo.GetString("template", "", p)
	withCxt := cookoo.GetBool("template.Context", false, p)

	name := fmt.Sprintf("%x", md5.Sum([]byte(format)))

	//c.Logf("debug", "Template %s is '%s'\n", name, format)

	tpl, err := template.New(name).Parse(format)
	if err != nil {
		return "", err
	}

	data := p.AsMap()
	if withCxt {
		//c.Logf("debug", "Adding context.")
		data["Cxt"] = c.AsMap()
	}

	var out bytes.Buffer
	if err := tpl.Execute(&out, data); err != nil {
		return "", err
	}

	return out.String(), nil
}
Example #3
0
// Get gets one or more environment variables and puts them into the context.
//
// Parameters passed in are of the form varname => defaultValue.
//
// 	r.Route("foo", "example").Does(envvar.Get).Using("HOME").WithDefault(".")
//
// As with all environment variables, the default value must be a string.
//
// WARNING: Since parameters are a map, order of processing is not
// guaranteed. If order is important, you'll need to call this command
// multiple times.
//
// For each parameter (`Using` clause), this command will look into the
// environment for a matching variable. If it finds one, it will add that
// variable to the context. If it does not find one, it will expand the
// default value (so you can set a default to something like "$HOST:$PORT")
// and also put the (unexpanded) default value back into the context in case
// any subsequent call to `os.Getenv` occurs.
func Get(c cookoo.Context, params *cookoo.Params) (interface{}, cookoo.Interrupt) {
	for name, def := range params.AsMap() {
		var val string
		if val = os.Getenv(name); len(val) == 0 {
			def := def.(string)
			val = os.ExpandEnv(def)
			// We want to make sure that any subsequent calls to Getenv
			// return the same default.
			os.Setenv(name, val)

		}
		c.Put(name, val)
		log.Debugf(c, "Name: %s, Val: %s", name, val)
	}
	return true, nil
}
Example #4
0
File: envvar.go Project: helgi/pkg
// Set takes the given names and values and puts them into both the context
// and the environment.
//
// Unlike Get, it does not try to retrieve the values from the environment
// first.
//
// Values are passed through os.ExpandEnv()
//
// There is no guarantee of insertion order. If multiple name/value pairs
// are given, they will be put into the context in whatever order they
// are retrieved from the underlying map.
//
// Params:
//   accessed as map[string]string
// Returns:
//   nothing, but inserts all name/value pairs into the context and the
//   environment.
func Set(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	for name, def := range p.AsMap() {
		// Assume Nil means unset the value.
		if def == nil {
			def = ""
		}

		val := fmt.Sprintf("%v", def)
		val = os.ExpandEnv(val)
		log.Debugf(c, "Name: %s, Val: %s", name, val)

		os.Setenv(name, val)
		c.Put(name, val)
	}
	return true, nil

}
Example #5
0
// Sprintf formats a string and then returns the result to the context.
//
// This is a command wrapper for the core `fmt.Sprintf` function, but tooled
// to work the Cookoo way.
//
// The following returns 'Hello World' to the context.
//
// 	//...
// 	Does(Sprintf, "out").
// 	Using("format").WithDefault("%s %s\n")
// 	Using("0").WithDefault("Hello")
// 	Using("1").WithDefault("World")
//
// Params:
// 	- format (string): The format string
// 	- "0"... (string): String representation of an integer ascending from 0.
// 	  These are treated as positional.
func Sprintf(c cookoo.Context, params *cookoo.Params) (interface{}, cookoo.Interrupt) {
	msg := params.Get("format", "").(string)

	maxP := len(params.AsMap())
	vals := make([]interface{}, 0, maxP-1)

	var istr string
	var i = 0
	for i < maxP {
		istr = fmt.Sprintf("%d", i) // FIXME
		if v, ok := params.Has(istr); ok {
			//fmt.Printf("%d: Found %v\n", i, v)
			vals = append(vals, v)
			i++
		} else {
			break
		}
	}

	return fmt.Sprintf(msg, vals...), nil
}
Example #6
0
File: envvar.go Project: helgi/pkg
// Get gets one or more environment variables and puts them into the context.
//
// Parameters passed in are of the form varname => defaultValue.
//
// 	r.Route("foo", "example").Does(envvar.Get).Using("HOME").WithDefault(".")
//
// As with all environment variables, the default value must be a string.
//
// WARNING: Since parameters are a map, order of processing is not
// guaranteed. If order is important, you'll need to call this command
// multiple times.
//
// For each parameter (`Using` clause), this command will look into the
// environment for a matching variable. If it finds one, it will add that
// variable to the context. If it does not find one, it will expand the
// default value (so you can set a default to something like "$HOST:$PORT")
// and also put the (unexpanded) default value back into the context in case
// any subsequent call to `os.Getenv` occurs.
func Get(c cookoo.Context, params *cookoo.Params) (interface{}, cookoo.Interrupt) {
	for name, def := range params.AsMap() {
		var val string
		if val = os.Getenv(name); len(val) == 0 {
			if def == nil {
				def = ""
			}
			def, ok := def.(string)
			if !ok {
				log.Warnf(c, "Could not convert %s. Type is %T", name, def)
			}
			val = os.ExpandEnv(def)
			// We want to make sure that any subsequent calls to Getenv
			// return the same default.
			os.Setenv(name, val)

		}
		c.Put(name, val)
		log.Debugf(c, "Name: %s, Val: %s", name, val)
	}
	return true, nil
}
Example #7
0
// KillOnExit kills PIDs when the program exits.
//
// Otherwise, this blocks until an os.Interrupt or os.Kill is received.
//
// Params:
//  This treats Params as a map of process names (unimportant) to PIDs. It then
// attempts to kill all of the pids that it receives.
func KillOnExit(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	sigs := make(chan os.Signal, 1)
	signal.Notify(sigs, os.Interrupt, os.Kill)

	safely.GoDo(c, func() {
		log.Info(c, "Builder is running.")

		<-sigs

		c.Log("info", "Builder received signal to stop.")
		pids := p.AsMap()
		killed := 0
		for name, pid := range pids {
			if pid, ok := pid.(int); ok {
				if proc, err := os.FindProcess(pid); err == nil {
					log.Infof(c, "Killing %s (pid=%d)", name, pid)
					proc.Kill()
					killed++
				}
			}
		}
	})
	return nil, nil
}