Exemple #1
0
// WriteYaml writes the config as YAML.
//
// Params:
//	- conf: A *cfg.Config to render.
// 	- out (io.Writer): An output stream to write to. Default is os.Stdout.
// 	- filename (string): If set, the file will be opened and the content will be written to it.
func WriteYaml(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	conf := p.Get("conf", nil).(*cfg.Config)
	toStdout := p.Get("toStdout", true).(bool)

	data, err := conf.Marshal()
	if err != nil {
		return nil, err
	}

	var out io.Writer
	if nn, ok := p.Has("filename"); ok && len(nn.(string)) > 0 {
		file, err := os.Create(nn.(string))
		if err != nil {
		}
		defer file.Close()
		out = io.Writer(file)
		//fmt.Fprint(out, yml)
		out.Write(data)
	} else if toStdout {
		out = p.Get("out", os.Stdout).(io.Writer)
		//fmt.Fprint(out, yml)
		out.Write(data)
	}

	// Otherwise we supress output.
	return true, nil
}
Exemple #2
0
// Watch watches a given path, and executes a git check-repos for each event.
//
// It starts the watcher and then returns. The watcher runs on its own
// goroutine. To stop the watching, send the returned channel a bool.
//
// Params:
// - client (Watcher): An Etcd client.
// - path (string): The path to watch
//
// Returns:
// 	- chan bool: Send this a message to stop the watcher.
func Watch(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	// etcdctl -C $ETCD watch --recursive /deis/services
	path := p.Get("path", "/deis/services").(string)
	cli, ok := p.Has("client")
	if !ok {
		return nil, errors.New("No etcd client found.")
	}
	client := cli.(Watcher)

	// Stupid hack because etcd watch seems to be broken, constantly complaining
	// that the JSON it received is malformed.
	safely.GoDo(c, func() {
		for {
			response, err := client.Watch(path, 0, true, nil, nil)
			if err != nil {
				log.Errf(c, "Etcd Watch failed: %s", err)
				time.Sleep(50 * time.Millisecond)
				continue
			}

			if response.Node == nil {
				log.Infof(c, "Unexpected Etcd message: %v", response)
			}
			git := exec.Command("/home/git/check-repos")
			if out, err := git.CombinedOutput(); err != nil {
				log.Errf(c, "Failed git check-repos: %s", err)
				log.Infof(c, "Output: %s", out)
			}
		}

	})

	return nil, nil

}
Exemple #3
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
}
Exemple #4
0
// Recurse does glide installs on dependent packages.
// Recurse looks in all known packages for a glide.yaml files and installs for
// each one it finds.
func Recurse(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	if !p.Get("enable", true).(bool) {
		return nil, nil
	}
	force := p.Get("force", true).(bool)

	godeps, gpm, gb, deleteFlatten := false, false, false, false
	if g, ok := p.Has("importGodeps"); ok {
		godeps = g.(bool)
	}
	if g, ok := p.Has("importGPM"); ok {
		gpm = g.(bool)
	}
	if g, ok := p.Has("importGb"); ok {
		gb = g.(bool)
	}

	if g, ok := p.Has("deleteFlatten"); ok {
		deleteFlatten = g.(bool)
	}

	Info("Checking dependencies for updates. Godeps: %v, GPM: %v, gb: %v\n", godeps, gpm, gb)
	if deleteFlatten == true {
		Info("Deleting flattened dependencies enabled\n")
	}
	conf := p.Get("conf", &Config{}).(*Config)
	vend, _ := VendorPath(c)

	return recDepResolve(conf, vend, godeps, gpm, gb, force, deleteFlatten)
}
Exemple #5
0
// WriteYaml writes a yaml.Node to the console as a string.
//
// Params:
//	- yaml.Node (yaml.Node): A yaml.Node to render.
// 	- out (io.Writer): An output stream to write to. Default is os.Stdout.
// 	- filename (string): If set, the file will be opened and the content will be written to it.
func WriteYaml(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	top := p.Get("yaml.Node", yaml.Scalar("nothing to print")).(yaml.Node)
	var out io.Writer
	if nn, ok := p.Has("filename"); ok && len(nn.(string)) > 0 {
		file, err := os.Create(nn.(string))
		if err != nil {
		}
		defer file.Close()
		out = io.Writer(file)
	} else {
		out = p.Get("out", os.Stdout).(io.Writer)
	}

	fmt.Fprint(out, yaml.Render(top))

	return true, nil
}
Exemple #6
0
// Get performs an etcd Get operation.
//
// Params:
// 	- client (EtcdGetter): Etcd client
// 	- path (string): The path/key to fetch
//
// Returns:
// - This puts an `etcd.Response` into the context, and returns an error
//   if the client could not connect.
func Get(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	cli, ok := p.Has("client")
	if !ok {
		return nil, errors.New("No Etcd client found.")
	}
	client := cli.(Getter)
	path := p.Get("path", "/").(string)

	res, err := client.Get(path, false, false)
	if err != nil {
		return res, err
	}

	if !res.Node.Dir {
		return res, fmt.Errorf("Expected / to be a dir.")
	}
	return res, nil
}
Exemple #7
0
// Recurse does glide installs on dependent packages.
// Recurse looks in all known packages for a glide.yaml files and installs for
// each one it finds.
func Recurse(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	if !p.Get("enable", true).(bool) {
		return nil, nil
	}
	force := p.Get("force", true).(bool)

	godeps, gpm := false, false
	if g, ok := p.Has("importGodeps"); ok {
		godeps = g.(bool)
	}
	if g, ok := p.Has("importGPM"); ok {
		gpm = g.(bool)
	}

	Info("Checking dependencies for updates. Godeps: %v, GPM: %v\n", godeps, gpm)
	conf := p.Get("conf", &Config{}).(*Config)
	vend, _ := VendorPath(c)

	return recDepResolve(conf, vend, godeps, gpm, force)
}
Exemple #8
0
// MakeDir makes a directory in Etcd.
//
// Params:
// 	- client (EtcdDirCreator): Etcd client
//  - path (string): The name of the directory to create.
// 	- ttl (uint64): Time to live.
// Returns:
// 	*etcd.Response
func MakeDir(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	name := p.Get("path", "").(string)
	ttl := p.Get("ttl", uint64(0)).(uint64)
	cli, ok := p.Has("client")
	if !ok {
		return nil, errors.New("No Etcd client found.")
	}
	client := cli.(DirCreator)

	if len(name) == 0 {
		return false, errors.New("Expected directory name to be more than zero characters.")
	}

	res, err := client.CreateDir(name, ttl)
	if err != nil {
		return res, &cookoo.RecoverableError{err.Error()}
	}

	return res, nil
}
Exemple #9
0
// ServeFiles is a cookoo command to serve files from a set of filesystem directories.
//
// If no writer is specified, this will attempt to write to whatever is in the
// Context with the key "http.ResponseWriter". If no suitable writer is found, it will
// not write to anything at all.
//
// Example:
//
//     registry.Route("GET /**", "Serve assets").
//         Does(web.ServeFiles, "fileServer").
//            Using("directory").WithDefault("static")
//
// Example 2:
//
//     registry.Route("GET /foo/**", "Serve assets").
//         Does(web.ServeFiles, "fileServer").
//             Using("directory").WithDefault("static").
//             Using("removePrefix").WithDefault("/foo")
//
// Params:
// 	- directory: A directory to serve files from.
// 	- removePrefix: A prefix to remove from the url before looking for it on the filesystem.
// 	- writer: A Writer of some sort. This will try to write to the HTTP response if no writer
// 	  is specified.
// 	- request: A request of some sort. This will try to use the HTTP request if no request
// 	  is specified.
func ServeFiles(cxt cookoo.Context, params *cookoo.Params) (interface{}, cookoo.Interrupt) {

	writer, ok := params.Has("writer")
	if writer == nil {
		writer, ok = cxt.Has("http.ResponseWriter")
		if !ok {
			return nil, &cookoo.Reroute{"@404"}
		}
	}
	out := writer.(http.ResponseWriter)

	req, ok := params.Has("request")
	if req == nil {
		req, ok = cxt.Has("http.Request")
		if !ok {
			return nil, &cookoo.Reroute{"@404"}
		}
	}

	in := req.(*http.Request)

	directory := params.Get("directory", nil)
	if directory == nil {
		return nil, &cookoo.Reroute{"@404"}
	}

	prefix := params.Get("removePrefix", "").(string)
	urlPath := strings.TrimPrefix(in.URL.Path, prefix)
	staticFile := path.Join(directory.(string), urlPath)

	info, err := os.Stat(staticFile)
	if err != nil {
		return nil, &cookoo.Reroute{"@404"}
	}

	if info.IsDir() == false {
		http.ServeFile(out, in, staticFile)
		return true, nil
	}
	return nil, &cookoo.Reroute{"@404"}
}
Exemple #10
0
// Get performs an etcd Get operation.
//
// Params:
// 	- client (EtcdGetter): Etcd client
// 	- path (string): The path/key to fetch
// 	- recursive (bool): Get children, too. Default: false.
// 	- sort (bool): Lexigraphically sort by name. Default: false.
//
// Returns:
// - This puts an `etcd.Response` into the context, and returns an error
//   if the client could not connect.
func Get(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	cli, ok := p.Has("client")
	if !ok {
		return nil, errors.New("No Etcd client found.")
	}
	ec := cli.(client.Client)
	path := p.Get("path", "/").(string)
	rec := p.Get("recursive", false).(bool)
	sort := p.Get("sort", false).(bool)

	k := client.NewKeysAPI(ec)
	res, err := k.Get(dctx(), path, &client.GetOptions{Sort: sort, Recursive: rec})
	if err != nil {
		return res, err
	}

	if !res.Node.Dir {
		return res, fmt.Errorf("Expected / to be a dir.")
	}
	return res, nil
}
Exemple #11
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
}
Exemple #12
0
// Flush sends content to output.
//
// If no writer is specified, this will attempt to write to whatever is in the
// Context with the key "http.ResponseWriter". If no suitable writer is found, it will
// not write to anything at all.
//
// Params:
// 	- writer: A Writer of some sort. This will try to write to the HTTP response if no writer
// 	is specified.
// 	- content: The content to write as a body. If this is a byte[], it is sent unchanged. Otherwise.
// 	we first try to convert to a string, then pass it into a writer.
// 	- contentType: The content type header (e.g. text/html). Default is text/plain
// 	- responseCode: Integer HTTP Response Code: Default is `http.StatusOK`.
// 	- headers: a map[string]string of HTTP headers. The keys will be run through
// 	 http.CannonicalHeaderKey()
//
// Note that this is optimized for writing from strings or arrays, not Readers. For larger
// objects, you may find it more efficient to use a different command.
//
// Context:
// - If this finds `web.ContentEncoding`, it will set a content-encoding header.
//
// Returns
//
// 	- boolean true
func Flush(cxt cookoo.Context, params *cookoo.Params) (interface{}, cookoo.Interrupt) {

	// Make sure we have a place to write this stuff.
	writer, ok := params.Has("writer")
	if writer == nil {
		writer, ok = cxt.Has("http.ResponseWriter")
		if !ok {
			return false, nil
		}
	}
	out := writer.(http.ResponseWriter)

	// Get the rest of the info.
	code := params.Get("responseCode", http.StatusOK).(int)
	header := out.Header()
	contentType := params.Get("contentType", "text/plain; charset=utf-8").(string)

	// Prepare the content.
	var content []byte
	rawContent, ok := params.Has("content")
	if !ok {
		// No content. Send nothing in the body.
		content = []byte("")
	} else if byteContent, ok := rawContent.([]byte); ok {
		// Got a byte[]; add it as is.
		content = byteContent
	} else {
		// Use the formatter to convert to a string, and then
		// cast it to bytes.
		content = []byte(fmt.Sprintf("%v", rawContent))
	}

	// Add headers:
	header.Set(http.CanonicalHeaderKey("content-type"), contentType)

	te := cxt.Get(ContentEncoding, "").(string)
	if len(te) > 0 {
		header.Set(http.CanonicalHeaderKey("transfer-encoding"), te)
	}

	headerO, ok := params.Has("headers")
	if ok {
		headers := headerO.(map[string]string)
		for k, v := range headers {
			header.Add(http.CanonicalHeaderKey(k), v)
		}
	}

	// Send the headers.
	out.WriteHeader(code)

	//io.WriteString(out, content)
	out.Write(content)

	return true, nil
}
Exemple #13
0
// Watch watches a given path, and executes a git check-repos for each event.
//
// It starts the watcher and then returns. The watcher runs on its own
// goroutine. To stop the watching, send the returned channel a bool.
//
// Params:
// - client (Watcher): An Etcd client.
// - path (string): The path to watch
//
// Returns:
// 	- chan bool: Send this a message to stop the watcher.
func Watch(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	// etcdctl -C $ETCD watch --recursive /deis/services
	path := p.Get("path", "/deis/services").(string)
	cli, ok := p.Has("client")
	if !ok {
		return nil, errors.New("No etcd client found.")
	}
	client := cli.(Watcher)

	// Stupid hack because etcd watch seems to be broken, constantly complaining
	// that the JSON it received is malformed.
	safely.GoDo(c, func() {
		for {
			response, err := client.Watch(path, 0, true, nil, nil)
			if err != nil {
				log.Errf(c, "Etcd Watch failed: %s", err)
				time.Sleep(50 * time.Millisecond)
				continue
			}

			if response.Node == nil {
				log.Infof(c, "Unexpected Etcd message: %v", response)
			}
			git := exec.Command("/home/git/check-repos")
			if out, err := git.CombinedOutput(); err != nil {
				log.Errf(c, "Failed git check-repos: %s", err)
				log.Infof(c, "Output: %s", out)
			}
		}

	})

	return nil, nil

	/* Watch seems to be broken. So we do this stupid watch loop instead.
	receiver := make(chan *etcd.Response)
	stop := make(chan bool)
	// Buffer the channels so that we don't hang waiting for go-etcd to
	// read off the channel.
	stopetcd := make(chan bool, 1)
	stopwatch := make(chan bool, 1)


	// Watch for errors.
	safely.GoDo(c, func() {
		// When a receiver is passed in, no *Response is ever returned. Instead,
		// Watch acts like an error channel, and receiver gets all of the messages.
		_, err := client.Watch(path, 0, true, receiver, stopetcd)
		if err != nil {
			log.Infof(c, "Watcher stopped with error '%s'", err)
			stopwatch <- true
			//close(stopwatch)
		}
	})
	// Watch for events
	safely.GoDo(c, func() {
		for {
			select {
			case msg := <-receiver:
				if msg.Node != nil {
					log.Infof(c, "Received notification %s for %s", msg.Action, msg.Node.Key)
				} else {
					log.Infof(c, "Received unexpected etcd message: %v", msg)
				}
				git := exec.Command("/home/git/check-repos")
				if out, err := git.CombinedOutput(); err != nil {
					log.Errf(c, "Failed git check-repos: %s", err)
					log.Infof(c, "Output: %s", out)
				}
			case <-stopwatch:
				c.Logf("debug", "Received signal to stop watching events.")
				return
			}
		}
	})
	// Fan out stop requests.
	safely.GoDo(c, func() {
		<-stop
		stopwatch <- true
		stopetcd <- true
		close(stopwatch)
		close(stopetcd)
	})

	return stop, nil
	*/
}