<commit_before>package main

import (
	"github.com/gobs/args"
	"github.com/gobs/cmd"
	"github.com/gobs/httpclient"
	"github.com/gobs/simplejson"
	"github.com/oliveagle/jsonpath"

	"fmt"
	"net/url"
	"os"
	"strconv"
	"strings"
	"time"
)

var (
	completion_words = []string{}
	env              = map[string]string{}
)

func CompletionFunction(text, line string) (matches []string) {
	// for the "ls" command we let readline show real file names
	if strings.HasPrefix(line, "ls ") {
		return
	}

	// for all other commands, we pick from our list of completion words
	for _, w := range completion_words {
		if strings.HasPrefix(w, text) {
			matches = append(matches, w)
		}
	}

	return
}

func request(client *httpclient.HttpClient, method, params string) *httpclient.HttpResponse {
	env["error"] = ""
	env["body"] = ""

	options := []httpclient.RequestOption{client.Method(method)}
	args := args.ParseArgs(params)

	if len(args.Arguments) > 0 {
		options = append(options, client.Path(args.Arguments[0]))
	}

	if len(args.Arguments) > 1 {
		data := strings.Join(args.Arguments[1:], " ")
		options = append(options, client.Body(strings.NewReader(data)))
	}

	if len(args.Options) > 0 {
		options = append(options, client.StringParams(args.Options))
	}

	res, err := client.SendRequest(options...)
	if err == nil {
		err = res.ResponseError()
	}
	if err != nil {
		fmt.Println("ERROR:", err)
		env["error"] = err.Error()
	}

	body := res.Content()
	if len(body) > 0 {
		if strings.Contains(res.Header.Get("Content-Type"), "json") {
			jbody, err := simplejson.LoadBytes(body)
			if err != nil {
				fmt.Println(err)
			} else {
				printJson(jbody.Data())
			}
		} else {
			fmt.Println(string(body))
		}
	}

	env["body"] = string(body)
	return res
}

func headerName(s string) string {
	s = strings.ToLower(s)
	parts := strings.Split(s, "-")
	for i, p := range parts {
		if len(p) > 0 {
			parts[i] = strings.ToUpper(p[0:1]) + p[1:]
		}
	}
	return strings.Join(parts, "-")
}

func unquote(s string) string {
	if res, err := strconv.Unquote(strings.TrimSpace(s)); err == nil {
		return res
	}

	return s
}

func printJson(v interface{}) {
        fmt.Println(simplejson.MustDumpString(v, simplejson.Indent("  ")))
}

func main() {
	var interrupted bool
	var client = httpclient.NewHttpClient("")

	client.UserAgent = "httpclient/0.1"

	commander := &cmd.Cmd{
		HistoryFile: ".httpclient_history",
		Complete:    CompletionFunction,
		EnableShell: true,
		Interrupt:   func(sig os.Signal) bool { interrupted = true; return false },
	}

	commander.Init()

	commander.Vars = env

	commander.Add(cmd.Command{
		"base",
		`base [url]`,
		func(line string) (stop bool) {
			if line != "" {
				val, err := url.Parse(line)
				if err != nil {
					fmt.Println(err)
					return
				}

				client.BaseURL = val
				commander.Prompt = fmt.Sprintf("%v> ", client.BaseURL)
			}

			fmt.Println("base", client.BaseURL)
			return
		},
		nil})

	commander.Add(cmd.Command{
		"insecure",
		`insecure [true|false]`,
		func(line string) (stop bool) {
			if line != "" {
				val, err := strconv.ParseBool(line)
				if err != nil {
					fmt.Println(err)
					return
				}

				client.AllowInsecure(val)
			}

			// assume if there is a transport, it's because we set AllowInsecure
			fmt.Println("insecure", client.GetTransport() != nil)

			return
		},
		nil})

	commander.Add(cmd.Command{
		"timeout",
		`timeout [duration]`,
		func(line string) (stop bool) {
			if line != "" {
				val, err := time.ParseDuration(line)
				if err != nil {
					fmt.Println(err)
					return
				}

				client.SetTimeout(val)
			}

			fmt.Println("timeout", client.GetTimeout())
			return
		},
		nil})

	commander.Add(cmd.Command{
		"verbose",
		`verbose [true|false]`,
		func(line string) (stop bool) {
			if line != "" {
				val, err := strconv.ParseBool(line)
				if err != nil {
					fmt.Println(err)
					return
				}

				client.Verbose = val
			}

			fmt.Println("Verbose", client.Verbose)
			return
		},
		nil})

	commander.Add(cmd.Command{
		"agent",
		`agent user-agent-string`,
		func(line string) (stop bool) {
			if line != "" {
				client.UserAgent = line
			}

			fmt.Println("User-Agent:", client.UserAgent)
			return
		},
		nil})

	commander.Add(cmd.Command{
		"header",
		`header [name [value]]`,
		func(line string) (stop bool) {
			if line == "" {
				if len(client.Headers) == 0 {
					fmt.Println("No headers")
				} else {
					fmt.Println("Headers:")
					for k, v := range client.Headers {
						fmt.Printf("  %v: %v\n", k, v)
					}
				}

				return
			}

			parts := args.GetArgsN(line, 2)
			name := headerName(parts[0])

			if len(parts) == 2 {
				client.Headers[name] = unquote(parts[1])
			}

			fmt.Printf("%v: %v\n", name, client.Headers[name])
			return
		},
		nil})

	commander.Add(cmd.Command{"get",
		`
                get [url-path] [short-data]
                `,
		func(line string) (stop bool) {
			request(client, "get", line)
			return
		},
		nil})

	commander.Add(cmd.Command{"head",
		`
                head [url-path] [short-data]
                `,
		func(line string) (stop bool) {
			res := request(client, "head", line)
			if res != nil {
				printJson(res.Header)
			}
			return
		},
		nil})

	commander.Add(cmd.Command{"post",
		`
                post [url-path] [short-data]
                `,
		func(line string) (stop bool) {
			request(client, "post", line)
			return
		},
		nil})

	commander.Add(cmd.Command{"put",
		`
                put [url-path] [short-data]
                `,
		func(line string) (stop bool) {
			request(client, "put", line)
			return
		},
		nil})

	commander.Add(cmd.Command{"delete",
		`
                delete [url-path] [short-data]
                `,
		func(line string) (stop bool) {
			request(client, "delete", line)
			return
		},
		nil})

	commander.Add(cmd.Command{
		"jsonpath",
		`jsonpath path {json}`,
		func(line string) (stop bool) {
			parts := args.GetArgsN(line, 2)
			if len(parts) != 2 {
				fmt.Println("use: jsonpath path {json}")
				env["error"] = "invalid-usage"
				return
			}

			path := parts[0]
			if !strings.HasPrefix(path, "$.") {
				path = "$." + path
			}

			jbody, err := simplejson.LoadString(parts[1])
			if err != nil {
				fmt.Println("json:", err)
				env["error"] = err.Error()
				return
			}

			res, err := jsonpath.JsonPathLookup(jbody.Data(), path)
			if err != nil {
				fmt.Println("jsonpath:", err)
				env["error"] = err.Error()
			} else {
				fmt.Println(simplejson.MustDumpString(res, simplejson.Indent("  ")))
				env["error"] = ""
				env["json"] = unquote(simplejson.MustDumpString(res))
			}

			return
		},
		nil})

	commander.Add(cmd.Command{
		"format",
		`format object`,
		func(line string) (stop bool) {
			jbody, err := simplejson.LoadString(line)
			if err != nil {
				fmt.Println("json:", err)
				env["error"] = err.Error()
				return
			}

                        printJson(jbody.Data())
                        return
		},
		nil})
	commander.Add(cmd.Command{
		"exit",
		`exit script`,
		func(line string) (stop bool) {
			fmt.Println("goodbye!")
			return true
		},
		nil})

	switch len(os.Args) {
	case 1: // program name only
		break

	case 2: // one arg - expect URL or @filename
		cmd := os.Args[1]
		if !strings.HasPrefix(cmd, "@") {
			cmd = "base " + cmd
		}

		commander.OneCmd(cmd)

	default:
		fmt.Println("usage:", os.Args[0], "[base-url]")
		return
	}

	commander.CmdLoop()
}
<commit_msg>Added "print" variable, to disable automatic printing of responses. Also switch to our own jsonpath.<commit_after>package main

import (
	"github.com/gobs/args"
	"github.com/gobs/cmd"
	"github.com/gobs/httpclient"
	"github.com/gobs/jsonpath"
	"github.com/gobs/simplejson"

	"fmt"
	"net/url"
	"os"
	"strconv"
	"strings"
	"time"
)

var (
	completion_words = []string{}
	env              = map[string]string{}
)

func CompletionFunction(text, line string) (matches []string) {
	// for the "ls" command we let readline show real file names
	if strings.HasPrefix(line, "ls ") {
		return
	}

	// for all other commands, we pick from our list of completion words
	for _, w := range completion_words {
		if strings.HasPrefix(w, text) {
			matches = append(matches, w)
		}
	}

	return
}

func request(client *httpclient.HttpClient, method, params string, print bool) *httpclient.HttpResponse {
	env["error"] = ""
	env["body"] = ""

	options := []httpclient.RequestOption{client.Method(method)}
	args := args.ParseArgs(params)

	if len(args.Arguments) > 0 {
		options = append(options, client.Path(args.Arguments[0]))
	}

	if len(args.Arguments) > 1 {
		data := strings.Join(args.Arguments[1:], " ")
		options = append(options, client.Body(strings.NewReader(data)))
	}

	if len(args.Options) > 0 {
		options = append(options, client.StringParams(args.Options))
	}

	res, err := client.SendRequest(options...)
	if err == nil {
		err = res.ResponseError()
	}
	if err != nil {
		fmt.Println("ERROR:", err)
		env["error"] = err.Error()
	}

	body := res.Content()
	if len(body) > 0 && print {
		if strings.Contains(res.Header.Get("Content-Type"), "json") {
			jbody, err := simplejson.LoadBytes(body)
			if err != nil {
				fmt.Println(err)
			} else {
				printJson(jbody.Data())
			}
		} else {
			fmt.Println(string(body))
		}
	}

	env["body"] = string(body)
	return res
}

func headerName(s string) string {
	s = strings.ToLower(s)
	parts := strings.Split(s, "-")
	for i, p := range parts {
		if len(p) > 0 {
			parts[i] = strings.ToUpper(p[0:1]) + p[1:]
		}
	}
	return strings.Join(parts, "-")
}

func unquote(s string) string {
	if res, err := strconv.Unquote(strings.TrimSpace(s)); err == nil {
		return res
	}

	return s
}

func printJson(v interface{}) {
	fmt.Println(simplejson.MustDumpString(v, simplejson.Indent("  ")))
}

func main() {
	var interrupted bool
	var client = httpclient.NewHttpClient("")

	client.UserAgent = "httpclient/0.1"

	commander := &cmd.Cmd{
		HistoryFile: ".httpclient_history",
		Complete:    CompletionFunction,
		EnableShell: true,
		Interrupt:   func(sig os.Signal) bool { interrupted = true; return false },
	}

	commander.Init()

	commander.Vars = env
	commander.SetVar("print", true)

	commander.Add(cmd.Command{
		"base",
		`base [url]`,
		func(line string) (stop bool) {
			if line != "" {
				val, err := url.Parse(line)
				if err != nil {
					fmt.Println(err)
					return
				}

				client.BaseURL = val
				commander.Prompt = fmt.Sprintf("%v> ", client.BaseURL)
				if !commander.GetBoolVar("print") {
					return
				}
			}

			fmt.Println("base", client.BaseURL)
			return
		},
		nil})

	commander.Add(cmd.Command{
		"insecure",
		`insecure [true|false]`,
		func(line string) (stop bool) {
			if line != "" {
				val, err := strconv.ParseBool(line)
				if err != nil {
					fmt.Println(err)
					return
				}

				client.AllowInsecure(val)
			}

			// assume if there is a transport, it's because we set AllowInsecure
			fmt.Println("insecure", client.GetTransport() != nil)

			return
		},
		nil})

	commander.Add(cmd.Command{
		"timeout",
		`timeout [duration]`,
		func(line string) (stop bool) {
			if line != "" {
				val, err := time.ParseDuration(line)
				if err != nil {
					fmt.Println(err)
					return
				}

				client.SetTimeout(val)
			}

			fmt.Println("timeout", client.GetTimeout())
			return
		},
		nil})

	commander.Add(cmd.Command{
		"verbose",
		`verbose [true|false]`,
		func(line string) (stop bool) {
			if line != "" {
				val, err := strconv.ParseBool(line)
				if err != nil {
					fmt.Println(err)
					return
				}

				client.Verbose = val
			}

			fmt.Println("Verbose", client.Verbose)
			return
		},
		nil})

	commander.Add(cmd.Command{
		"agent",
		`agent user-agent-string`,
		func(line string) (stop bool) {
			if line != "" {
				client.UserAgent = line
			}

			fmt.Println("User-Agent:", client.UserAgent)
			return
		},
		nil})

	commander.Add(cmd.Command{
		"header",
		`header [name [value]]`,
		func(line string) (stop bool) {
			if line == "" {
				if len(client.Headers) == 0 {
					fmt.Println("No headers")
				} else {
					fmt.Println("Headers:")
					for k, v := range client.Headers {
						fmt.Printf("  %v: %v\n", k, v)
					}
				}

				return
			}

			parts := args.GetArgsN(line, 2)
			name := headerName(parts[0])

			if len(parts) == 2 {
				client.Headers[name] = unquote(parts[1])
				if !commander.GetBoolVar("print") {
					return
				}
			}

			fmt.Printf("%v: %v\n", name, client.Headers[name])
			return
		},
		nil})

	commander.Add(cmd.Command{"head",
		`
                head [url-path] [short-data]
                `,
		func(line string) (stop bool) {
			res := request(client, "head", line, false)
			if res != nil {
				printJson(res.Header)
			}
			return
		},
		nil})

	commander.Add(cmd.Command{"get",
		`
                get [url-path] [short-data]
                `,
		func(line string) (stop bool) {
			request(client, "get", line, commander.GetBoolVar("print"))
			return
		},
		nil})

	commander.Add(cmd.Command{"post",
		`
                post [url-path] [short-data]
                `,
		func(line string) (stop bool) {
			request(client, "post", line, commander.GetBoolVar("print"))
			return
		},
		nil})

	commander.Add(cmd.Command{"put",
		`
                put [url-path] [short-data]
                `,
		func(line string) (stop bool) {
			request(client, "put", line, commander.GetBoolVar("print"))
			return
		},
		nil})

	commander.Add(cmd.Command{"delete",
		`
                delete [url-path] [short-data]
                `,
		func(line string) (stop bool) {
			request(client, "delete", line, commander.GetBoolVar("print"))
			return
		},
		nil})

	commander.Add(cmd.Command{
		"jsonpath",
		`jsonpath path {json}`,
		func(line string) (stop bool) {
			parts := args.GetArgsN(line, 2)
			if len(parts) != 2 {
				fmt.Println("use: jsonpath path {json}")
				env["error"] = "invalid-usage"
				return
			}

			path := parts[0]
			if !strings.HasPrefix(path, "$.") {
				path = "$." + path
			}

			jbody, err := simplejson.LoadString(parts[1])
			if err != nil {
				fmt.Println("json:", err)
				env["error"] = err.Error()
				return
			}

			jp := jsonpath.NewProcessor()
			if err := jp.Parse(path); err != nil {
				env["error"] = fmt.Sprintf("failed to parse %q", path)
				return // syntax error
			}

			res := jp.Process(jbody)
			if commander.GetBoolVar("print") {
				printJson(res)
			}
			env["error"] = ""
			env["json"] = unquote(simplejson.MustDumpString(res))
			return
		},
		nil})

	commander.Add(cmd.Command{
		"format",
		`format object`,
		func(line string) (stop bool) {
			jbody, err := simplejson.LoadString(line)
			if err != nil {
				fmt.Println("json:", err)
				env["error"] = err.Error()
				return
			}

			printJson(jbody.Data())
			return
		},
		nil})
	commander.Add(cmd.Command{
		"exit",
		`exit script`,
		func(line string) (stop bool) {
			fmt.Println("goodbye!")
			return true
		},
		nil})

	commander.Commands["set"] = commander.Commands["var"]

	switch len(os.Args) {
	case 1: // program name only
		break

	case 2: // one arg - expect URL or @filename
		cmd := os.Args[1]
		if !strings.HasPrefix(cmd, "@") {
			cmd = "base " + cmd
		}

		commander.OneCmd(cmd)

	default:
		fmt.Println("usage:", os.Args[0], "[base-url]")
		return
	}

	commander.CmdLoop()
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/kishaningithub/randomtext"
	"os"
	"regexp"
	"strconv"
	"strings"
)

func main() {
	sizePtr := flag.String("size", "1MB", "Size of generated random text in KB, MB, GB, TB")
	typePtr := flag.String("type", "chars", "Type of text to be generated - chars, words, zeros")
	flag.Parse()
	sizeInBytes := parseSize(*sizePtr)
	generator := parseType(*typePtr)
	randomtext.Generate(sizeInBytes, generator, os.Stdout)
}

func parseSize(sizePtr string) int {
	reg := regexp.MustCompile("\\d+")
	givenSize, _ := strconv.Atoi(reg.FindString(sizePtr))
	sizeInBytes := 1
	if strings.Contains(sizePtr, "KB") {
		sizeInBytes = givenSize * 1024
	} else if strings.Contains(sizePtr, "MB") {
		sizeInBytes = givenSize * 1024 * 1024
	} else if strings.Contains(sizePtr, "GB") {
		sizeInBytes = givenSize * 1024 * 1024 * 1024
	} else if strings.Contains(sizePtr, "TB") {
		sizeInBytes = givenSize * 1024 * 1024 * 1024 * 1024
	}
	return sizeInBytes
}

func parseType(typeStr string) func() string {
	switch typeStr {
	case "chars":
		return randomtext.CharGenerator()
	case "words":
		return randomtext.WordGenerator()
	case "zeros":
		return randomtext.ZeroGenerator()
	default:
		fmt.Print("Not a valid value")
		os.Exit(1)
	}
	return nil
}
<commit_msg>Make the size unit case insensitive<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/kishaningithub/randomtext"
	"os"
	"regexp"
	"strconv"
	"strings"
)

func main() {
	sizePtr := flag.String("size", "1MB", "Size of generated random text in KB, MB, GB, TB")
	typePtr := flag.String("type", "chars", "Type of text to be generated - chars, words, zeros")
	flag.Parse()
	sizeInBytes := parseSize(strings.ToLower(*sizePtr))
	generator := parseType(strings.ToLower(*typePtr))
	randomtext.Generate(sizeInBytes, generator, os.Stdout)
}

func parseSize(size string) int {
	reg := regexp.MustCompile("\\d+")
	givenSize, _ := strconv.Atoi(reg.FindString(size))
	sizeInBytes := 1
	if strings.Contains(size, "kb") {
		sizeInBytes = givenSize * 1024
	} else if strings.Contains(size, "mb") {
		sizeInBytes = givenSize * 1024 * 1024
	} else if strings.Contains(size, "gb") {
		sizeInBytes = givenSize * 1024 * 1024 * 1024
	} else if strings.Contains(size, "tb") {
		sizeInBytes = givenSize * 1024 * 1024 * 1024 * 1024
	}
	return sizeInBytes
}

func parseType(typeStr string) func() string {
	switch typeStr {
	case "chars":
		return randomtext.CharGenerator()
	case "words":
		return randomtext.WordGenerator()
	case "zeros":
		return randomtext.ZeroGenerator()
	default:
		fmt.Print("Not a valid value")
		os.Exit(1)
	}
	return nil
}
<|endoftext|>


<commit_before>/**
 * Generates a date in YYYY-MM-DD format based on a relative time
 * description (e.g. -1 week, +3 years)
 *
 * @author R. S. Doiel, <rsdoiel@gmail.com>
 * copyright (c) 2014 all rights reserved.
 * Released under the Simplified BSD License
 * See: http://opensource.org/licenses/bsd-license.php
 */
package main

import (
	reldate "../../"
	"flag"
	"fmt"
	"os"
	"strconv"
	"strings"
	"time"
)

var (
	help          bool
	endOfMonthFor bool
	relativeTo    string
	relativeT     time.Time
)

var usage = func(exit_code int, msg string) {
	var fh = os.Stderr
	if exit_code == 0 {
		fh = os.Stdout
	}
	fmt.Fprintf(fh, `%s
 USAGE %s [TIME_INCREMENT TIME_UNIT|WEEKDAY_NAME]

 EXAMPLES

 Two days from today: %s 2 days
 Three weeks ago: %s -- -3 weeks
 Three weeks from 2014-01-01: %s --from=2014-01-01 3 weeks
 Three days before 2014-01-01: %s --from=2014-01-01 -- -3 days
 The Friday of this week: %s Friday
 The Monday in week containing 2015-02-06: %s --from=2015-02-06 Monday

 Time increments are a positive or negative integer. Time unit can be
 either day(s), week(s), month(s), or year(s). Weekday names are
 case insentive (e.g. Monday and monday). They can be abbreviated
 to the first three letters of the name, e.g. Sunday can be Sun, Monday
 can be Mon, Tuesday can be Tue, Wednesday can be Wed, Thursday can
 be Thu, Friday can be Fri or Saturday can be Sat.

 OPTIONS

`, msg, os.Args[0], os.Args[0], os.Args[0], os.Args[0], os.Args[0], os.Args[0], os.Args[0])

	flag.VisitAll(func(f *flag.Flag) {
		fmt.Fprintf(fh, "\t-%s\t(defaults to %s) %s\n", f.Name, f.Value, f.Usage)
	})

	fmt.Fprintf(fh, `

 copyright (c) 2014 all rights reserved.
 Released under the Simplified BSD License
 See: http://opensource.org/licenses/bsd-license.php

`)
	os.Exit(exit_code)
}

func init() {
	const (
		relativeToUsage = "Date the relative time is calculated from."
		helpUsage       = "Display this help document."
		endOfMonthUsage = "Display the end of month day. E.g. 2012-02-29"
	)

	flag.StringVar(&relativeTo, "from", relativeTo, relativeToUsage)
	flag.StringVar(&relativeTo, "f", relativeTo, relativeToUsage)
	flag.BoolVar(&endOfMonthFor, "end-of-month", endOfMonthFor, endOfMonthUsage)
	flag.BoolVar(&help, "help", help, helpUsage)
	flag.BoolVar(&help, "h", help, helpUsage)
}

func assertOk(e error, failMsg string) {
	if e != nil {
		usage(1, fmt.Sprintf(" %s\n %s\n", failMsg, e))
	}
}

func main() {
	var (
		err        error
		unitString string
	)

	flag.Parse()
	if help == true {
		usage(0, "")
	}

	argc := flag.NArg()
	argv := flag.Args()

	if argc < 1 && endOfMonthFor == false {
		usage(1, "Missing time increment and units (e.g. +2 days) or weekday name (e.g. Monday, Mon).\n")
	} else if argc > 2 {
		usage(1, "Too many command line arguments.\n")
	}

	relativeT = time.Now()
	if relativeTo != "" {
		relativeT, err = time.Parse(reldate.YYYYMMDD, relativeTo)
		assertOk(err, "Cannot parse the from date.\n")
	}

	if endOfMonthFor == true {
		fmt.Println(reldate.EndOfMonth(relativeT))
		os.Exit(0)
	}

	timeInc := 0
	if argc == 2 {
		unitString = strings.ToLower(argv[1])
		timeInc, err = strconv.Atoi(argv[0])
		assertOk(err, "Time increment should be a positive or negative integer.\n")
	} else {
		// We may have a weekday string
		unitString = strings.ToLower(argv[0])
	}
	t, err := reldate.RelativeTime(relativeT, timeInc, unitString)
	assertOk(err, "Did not understand command.")
	fmt.Println(t.Format(reldate.YYYYMMDD))
}
<commit_msg>fixed import path in cmd<commit_after>/**
 * Generates a date in YYYY-MM-DD format based on a relative time
 * description (e.g. -1 week, +3 years)
 *
 * @author R. S. Doiel, <rsdoiel@gmail.com>
 * copyright (c) 2014 all rights reserved.
 * Released under the Simplified BSD License
 * See: http://opensource.org/licenses/bsd-license.php
 */
package main

import (
	"flag"
	"fmt"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/rsdoiel/reldate"
)

var (
	help          bool
	endOfMonthFor bool
	relativeTo    string
	relativeT     time.Time
)

var usage = func(exit_code int, msg string) {
	var fh = os.Stderr
	if exit_code == 0 {
		fh = os.Stdout
	}
	fmt.Fprintf(fh, `%s
 USAGE %s [TIME_INCREMENT TIME_UNIT|WEEKDAY_NAME]

 EXAMPLES

 Two days from today: %s 2 days
 Three weeks ago: %s -- -3 weeks
 Three weeks from 2014-01-01: %s --from=2014-01-01 3 weeks
 Three days before 2014-01-01: %s --from=2014-01-01 -- -3 days
 The Friday of this week: %s Friday
 The Monday in week containing 2015-02-06: %s --from=2015-02-06 Monday

 Time increments are a positive or negative integer. Time unit can be
 either day(s), week(s), month(s), or year(s). Weekday names are
 case insentive (e.g. Monday and monday). They can be abbreviated
 to the first three letters of the name, e.g. Sunday can be Sun, Monday
 can be Mon, Tuesday can be Tue, Wednesday can be Wed, Thursday can
 be Thu, Friday can be Fri or Saturday can be Sat.

 OPTIONS

`, msg, os.Args[0], os.Args[0], os.Args[0], os.Args[0], os.Args[0], os.Args[0], os.Args[0])

	flag.VisitAll(func(f *flag.Flag) {
		fmt.Fprintf(fh, "\t-%s\t(defaults to %s) %s\n", f.Name, f.Value, f.Usage)
	})

	fmt.Fprintf(fh, `

 copyright (c) 2014 all rights reserved.
 Released under the Simplified BSD License
 See: http://opensource.org/licenses/bsd-license.php

`)
	os.Exit(exit_code)
}

func init() {
	const (
		relativeToUsage = "Date the relative time is calculated from."
		helpUsage       = "Display this help document."
		endOfMonthUsage = "Display the end of month day. E.g. 2012-02-29"
	)

	flag.StringVar(&relativeTo, "from", relativeTo, relativeToUsage)
	flag.StringVar(&relativeTo, "f", relativeTo, relativeToUsage)
	flag.BoolVar(&endOfMonthFor, "end-of-month", endOfMonthFor, endOfMonthUsage)
	flag.BoolVar(&help, "help", help, helpUsage)
	flag.BoolVar(&help, "h", help, helpUsage)
}

func assertOk(e error, failMsg string) {
	if e != nil {
		usage(1, fmt.Sprintf(" %s\n %s\n", failMsg, e))
	}
}

func main() {
	var (
		err        error
		unitString string
	)

	flag.Parse()
	if help == true {
		usage(0, "")
	}

	argc := flag.NArg()
	argv := flag.Args()

	if argc < 1 && endOfMonthFor == false {
		usage(1, "Missing time increment and units (e.g. +2 days) or weekday name (e.g. Monday, Mon).\n")
	} else if argc > 2 {
		usage(1, "Too many command line arguments.\n")
	}

	relativeT = time.Now()
	if relativeTo != "" {
		relativeT, err = time.Parse(reldate.YYYYMMDD, relativeTo)
		assertOk(err, "Cannot parse the from date.\n")
	}

	if endOfMonthFor == true {
		fmt.Println(reldate.EndOfMonth(relativeT))
		os.Exit(0)
	}

	timeInc := 0
	if argc == 2 {
		unitString = strings.ToLower(argv[1])
		timeInc, err = strconv.Atoi(argv[0])
		assertOk(err, "Time increment should be a positive or negative integer.\n")
	} else {
		// We may have a weekday string
		unitString = strings.ToLower(argv[0])
	}
	t, err := reldate.RelativeTime(relativeT, timeInc, unitString)
	assertOk(err, "Did not understand command.")
	fmt.Println(t.Format(reldate.YYYYMMDD))
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"net/url"
	"os"
	"reflect"
	"runtime"
	"strings"

	"github.com/StackExchange/tcollector/collectors"
	"github.com/StackExchange/tcollector/opentsdb"
	"github.com/StackExchange/tcollector/queue"
)

var l = log.New(os.Stdout, "", log.LstdFlags)

var flagTest = flag.String("test", "", "Test collector matching pattern")
var flagList = flag.Bool("list", false, "List available collectors")
var host = flag.String("host", "", `OpenTSDB host. Ex: "tsdb.example.com". Can optionally specify port: "tsdb.example.com:4000", but will default to 4242 otherwise. If not specified, will print to screen`)

func main() {
	flag.Parse()
	u := parseHost()
	if *flagTest != "" {
		test(*flagTest)
		return
	} else if *flagList {
		list()
		return
	} else if *host != "" {
		if u == nil {
			l.Fatal("invalid host:", *host)
		}
	}

	cdp := collectors.Run()
	if u != nil {
		l.Println("OpenTSDB host:", u)
		queue.New(u.String(), cdp)
	} else {
		l.Println("Outputting to screen")
		printPut(cdp)
	}
	select {}
}

func test(s string) {
	for _, c := range collectors.Search(s) {
		md := c.F()
		for _, d := range md {
			l.Print(d.Telnet())
		}
	}
}

func list() {
	for _, c := range collectors.Search("") {
		v := runtime.FuncForPC(reflect.ValueOf(c).Pointer())
		l.Println(v.Name())
	}
}

func parseHost() *url.URL {
	if *host == "" {
		return nil
	}
	u := url.URL{
		Scheme: "http",
		Path:   "/api/put",
	}
	if !strings.Contains(*host, ":") {
		*host += ":4242"
	}
	u.Host = *host
	return &u
}

func printPut(c chan *opentsdb.DataPoint) {
	for dp := range c {
		l.Print(dp.Telnet())
	}
}
<commit_msg>cmd/scollector: Fix -list<commit_after>package main

import (
	"flag"
	"log"
	"net/url"
	"os"
	"reflect"
	"runtime"
	"strings"

	"github.com/StackExchange/tcollector/collectors"
	"github.com/StackExchange/tcollector/opentsdb"
	"github.com/StackExchange/tcollector/queue"
)

var l = log.New(os.Stdout, "", log.LstdFlags)

var flagTest = flag.String("test", "", "Test collector matching pattern")
var flagList = flag.Bool("list", false, "List available collectors")
var host = flag.String("host", "", `OpenTSDB host. Ex: "tsdb.example.com". Can optionally specify port: "tsdb.example.com:4000", but will default to 4242 otherwise. If not specified, will print to screen`)

func main() {
	flag.Parse()
	u := parseHost()
	if *flagTest != "" {
		test(*flagTest)
		return
	} else if *flagList {
		list()
		return
	} else if *host != "" {
		if u == nil {
			l.Fatal("invalid host:", *host)
		}
	}

	cdp := collectors.Run()
	if u != nil {
		l.Println("OpenTSDB host:", u)
		queue.New(u.String(), cdp)
	} else {
		l.Println("Outputting to screen")
		printPut(cdp)
	}
	select {}
}

func test(s string) {
	for _, c := range collectors.Search(s) {
		md := c.F()
		for _, d := range md {
			l.Print(d.Telnet())
		}
	}
}

func list() {
	for _, c := range collectors.Search("") {
		v := runtime.FuncForPC(reflect.ValueOf(c.F).Pointer())
		l.Println(v.Name())
	}
}

func parseHost() *url.URL {
	if *host == "" {
		return nil
	}
	u := url.URL{
		Scheme: "http",
		Path:   "/api/put",
	}
	if !strings.Contains(*host, ":") {
		*host += ":4242"
	}
	u.Host = *host
	return &u
}

func printPut(c chan *opentsdb.DataPoint) {
	for dp := range c {
		l.Print(dp.Telnet())
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

package ddl

import (
	"time"

	. "github.com/pingcap/check"
	"github.com/pingcap/tidb/kv"
	"github.com/pingcap/tidb/meta"
	"github.com/pingcap/tidb/model"
	"github.com/pingcap/tidb/util/testleak"
	"github.com/pingcap/tidb/util/types"
)

type testCtxKeyType int

func (k testCtxKeyType) String() string {
	return "test_ctx_key"
}

const testCtxKey testCtxKeyType = 0

func (s *testDDLSuite) TestReorg(c *C) {
	defer testleak.AfterTest(c)()
	store := testCreateStore(c, "test_reorg")
	defer store.Close()

	d := newDDL(store, nil, nil, testLease)
	defer d.Stop()

	time.Sleep(testLease)

	ctx := testNewContext(d)

	ctx.SetValue(testCtxKey, 1)
	c.Assert(ctx.Value(testCtxKey), Equals, 1)
	ctx.ClearValue(testCtxKey)

	err := ctx.NewTxn()
	c.Assert(err, IsNil)
	ctx.Txn().Set([]byte("a"), []byte("b"))
	err = ctx.Txn().Rollback()
	c.Assert(err, IsNil)

	err = ctx.NewTxn()
	c.Assert(err, IsNil)
	ctx.Txn().Set([]byte("a"), []byte("b"))
	err = ctx.Txn().Commit()
	c.Assert(err, IsNil)

	done := make(chan struct{})
	rowCount := int64(10)
	f := func() error {
		d.setReorgRowCount(rowCount)
		time.Sleep(4 * testLease)
		close(done)
		return nil
	}
	job := &model.Job{}
	err = d.runReorgJob(job, f)
	c.Assert(err, NotNil)

	<-done
	// Make sure the function of f is returned.
	time.Sleep(5 * time.Millisecond)
	err = d.runReorgJob(job, f)
	c.Assert(err, IsNil)
	c.Assert(job.RowCount, Equals, rowCount)
	c.Assert(d.reorgRowCount, Equals, int64(0))

	d.Stop()
	err = d.runReorgJob(job, func() error {
		time.Sleep(4 * testLease)
		return nil
	})
	c.Assert(err, NotNil)
	d.start()

	job = &model.Job{
		ID:       1,
		SchemaID: 1,
		Type:     model.ActionCreateSchema,
		Args:     []interface{}{model.NewCIStr("test")},
	}

	var info *reorgInfo
	err = kv.RunInNewTxn(d.store, false, func(txn kv.Transaction) error {
		t := meta.NewMeta(txn)
		var err1 error
		info, err1 = d.getReorgInfo(t, job)
		c.Assert(err1, IsNil)
		err1 = info.UpdateHandle(txn, 1)
		c.Assert(err1, IsNil)

		return nil
	})
	c.Assert(err, IsNil)

	err = kv.RunInNewTxn(d.store, false, func(txn kv.Transaction) error {
		t := meta.NewMeta(txn)
		var err1 error
		info, err1 = d.getReorgInfo(t, job)
		c.Assert(err1, IsNil)
		c.Assert(info.Handle, Greater, int64(0))
		return nil
	})
	c.Assert(err, IsNil)
}

func (s *testDDLSuite) TestReorgOwner(c *C) {
	defer testleak.AfterTest(c)()
	store := testCreateStore(c, "test_reorg_owner")
	defer store.Close()

	d1 := newDDL(store, nil, nil, testLease)
	defer d1.Stop()

	ctx := testNewContext(d1)

	testCheckOwner(c, d1, true, ddlJobFlag)

	d2 := newDDL(store, nil, nil, testLease)
	defer d2.Stop()

	dbInfo := testSchemaInfo(c, d1, "test")
	testCreateSchema(c, ctx, d1, dbInfo)

	tblInfo := testTableInfo(c, d1, "t", 3)
	testCreateTable(c, ctx, d1, dbInfo, tblInfo)

	t := testGetTable(c, d1, dbInfo.ID, tblInfo.ID)

	num := 10
	for i := 0; i < num; i++ {
		_, err := t.AddRecord(ctx, types.MakeDatums(i, i, i))
		c.Assert(err, IsNil)
	}

	err := ctx.Txn().Commit()
	c.Assert(err, IsNil)

	tc := &testDDLCallback{}
	tc.onJobRunBefore = func(job *model.Job) {
		if job.SchemaState == model.StateDeleteReorganization {
			d1.Stop()
		}
	}

	d1.setHook(tc)

	testDropSchema(c, ctx, d1, dbInfo)

	err = kv.RunInNewTxn(d1.store, false, func(txn kv.Transaction) error {
		t := meta.NewMeta(txn)
		db, err1 := t.GetDatabase(dbInfo.ID)
		c.Assert(err1, IsNil)
		c.Assert(db, IsNil)
		return nil
	})
	c.Assert(err, IsNil)
}
<commit_msg>ddl: make test stable (#3091)<commit_after>// Copyright 2015 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

package ddl

import (
	"time"

	. "github.com/pingcap/check"
	"github.com/pingcap/tidb/kv"
	"github.com/pingcap/tidb/meta"
	"github.com/pingcap/tidb/model"
	"github.com/pingcap/tidb/util/testleak"
	"github.com/pingcap/tidb/util/types"
)

type testCtxKeyType int

func (k testCtxKeyType) String() string {
	return "test_ctx_key"
}

const testCtxKey testCtxKeyType = 0

func (s *testDDLSuite) TestReorg(c *C) {
	defer testleak.AfterTest(c)()
	store := testCreateStore(c, "test_reorg")
	defer store.Close()

	d := newDDL(store, nil, nil, testLease)
	defer d.Stop()

	time.Sleep(testLease)

	ctx := testNewContext(d)

	ctx.SetValue(testCtxKey, 1)
	c.Assert(ctx.Value(testCtxKey), Equals, 1)
	ctx.ClearValue(testCtxKey)

	err := ctx.NewTxn()
	c.Assert(err, IsNil)
	ctx.Txn().Set([]byte("a"), []byte("b"))
	err = ctx.Txn().Rollback()
	c.Assert(err, IsNil)

	err = ctx.NewTxn()
	c.Assert(err, IsNil)
	ctx.Txn().Set([]byte("a"), []byte("b"))
	err = ctx.Txn().Commit()
	c.Assert(err, IsNil)

	rowCount := int64(10)
	f := func() error {
		d.setReorgRowCount(rowCount)
		time.Sleep(4 * testLease)
		return nil
	}
	job := &model.Job{}
	err = d.runReorgJob(job, f)
	c.Assert(err, NotNil)

	// The longest to wait for 5 seconds to make sure the function of f is returned.
	for i := 0; i < 1000; i++ {
		time.Sleep(5 * time.Millisecond)
		err = d.runReorgJob(job, f)
		if err == nil {
			c.Assert(job.RowCount, Equals, rowCount)
			c.Assert(d.reorgRowCount, Equals, int64(0))
			break
		}
	}
	c.Assert(err, IsNil)

	d.Stop()
	err = d.runReorgJob(job, func() error {
		time.Sleep(4 * testLease)
		return nil
	})
	c.Assert(err, NotNil)
	d.start()

	job = &model.Job{
		ID:       1,
		SchemaID: 1,
		Type:     model.ActionCreateSchema,
		Args:     []interface{}{model.NewCIStr("test")},
	}

	var info *reorgInfo
	err = kv.RunInNewTxn(d.store, false, func(txn kv.Transaction) error {
		t := meta.NewMeta(txn)
		var err1 error
		info, err1 = d.getReorgInfo(t, job)
		c.Assert(err1, IsNil)
		err1 = info.UpdateHandle(txn, 1)
		c.Assert(err1, IsNil)

		return nil
	})
	c.Assert(err, IsNil)

	err = kv.RunInNewTxn(d.store, false, func(txn kv.Transaction) error {
		t := meta.NewMeta(txn)
		var err1 error
		info, err1 = d.getReorgInfo(t, job)
		c.Assert(err1, IsNil)
		c.Assert(info.Handle, Greater, int64(0))
		return nil
	})
	c.Assert(err, IsNil)
}

func (s *testDDLSuite) TestReorgOwner(c *C) {
	defer testleak.AfterTest(c)()
	store := testCreateStore(c, "test_reorg_owner")
	defer store.Close()

	d1 := newDDL(store, nil, nil, testLease)
	defer d1.Stop()

	ctx := testNewContext(d1)

	testCheckOwner(c, d1, true, ddlJobFlag)

	d2 := newDDL(store, nil, nil, testLease)
	defer d2.Stop()

	dbInfo := testSchemaInfo(c, d1, "test")
	testCreateSchema(c, ctx, d1, dbInfo)

	tblInfo := testTableInfo(c, d1, "t", 3)
	testCreateTable(c, ctx, d1, dbInfo, tblInfo)

	t := testGetTable(c, d1, dbInfo.ID, tblInfo.ID)

	num := 10
	for i := 0; i < num; i++ {
		_, err := t.AddRecord(ctx, types.MakeDatums(i, i, i))
		c.Assert(err, IsNil)
	}

	err := ctx.Txn().Commit()
	c.Assert(err, IsNil)

	tc := &testDDLCallback{}
	tc.onJobRunBefore = func(job *model.Job) {
		if job.SchemaState == model.StateDeleteReorganization {
			d1.Stop()
		}
	}

	d1.setHook(tc)

	testDropSchema(c, ctx, d1, dbInfo)

	err = kv.RunInNewTxn(d1.store, false, func(txn kv.Transaction) error {
		t := meta.NewMeta(txn)
		db, err1 := t.GetDatabase(dbInfo.ID)
		c.Assert(err1, IsNil)
		c.Assert(db, IsNil)
		return nil
	})
	c.Assert(err, IsNil)
}
<|endoftext|>


<commit_before>// Package js provides functions for interacting with native JavaScript APIs. Calls to these functions are treated specially by GopherJS and translated directly to their JavaScript syntax.
//
// Type conversions between Go types and JavaScript types are performed automatically according to the following table:
//
//  | Go types                       | Go interface type              | JavaScript type |
//  | ------------------------------ | ------------------------------ | --------------- |
//  | bool                           | bool                           | Boolean         |
//  | int?, uint?, float?            | float64                        | Number          |
//  | string                         | string                         | String          |
//  | [?]int8                        | []int8                         | Int8Array       |
//  | [?]int16                       | []int16                        | Int16Array      |
//  | [?]int32, [?]int               | []int                          | Int32Array      |
//  | [?]uint8                       | []uint8                        | Int8Array       |
//  | [?]uint16                      | []uint16                       | Int16Array      |
//  | [?]uint32, [?]uint, [?]uintptr | []uint                         | Int32Array      |
//  | [?]float32                     | []float32                      | Float32Array    |
//  | [?]float64                     | []float64                      | Float64Array    |
//  | all other slices and arrays    | []interface{}                  | Array           |
//  | maps, structs                  | map[string]interface{}         | Object          |
//  | functions                      | func(...interface{}) js.Object | Function        |
//  | time.Time                      | time.Time                      | Date            |
//
// The second column denotes the types that are used when converting to `interface{}`. An exception are DOM elements, those are kept with the js.Object type. Additionally, a pointer to a named type is passed to JavaScript as an object which has wrappers for the type's exported methods. This can be used to provide getter and setter methods for Go fields to JavaScript.
package js

// Object is a container for a native JavaScript object. Calls to its methods are treated specially by GopherJS and translated directly to their JavaScript syntax.
type Object interface {

	// Get returns the object's property with the given key.
	Get(key string) Object

	// Set assigns the value to the object's property with the given key.
	Set(key string, value interface{})

	// Delete removes the object's property with the given key.
	Delete(key string)

	// Get returns the object's "length" property, converted to int.
	Length() int

	// Index returns the i'th element of an array.
	Index(i int) Object

	// SetIndex sets the i'th element of an array.
	SetIndex(i int, value interface{})

	// Call calls the object's method with the given name.
	Call(name string, args ...interface{}) Object

	// Invoke calls the object itself. This will fail if it is not a function.
	Invoke(args ...interface{}) Object

	// New creates a new instance of this type object. This will fail if it not a function (constructor).
	New(args ...interface{}) Object

	// Bool returns the object converted to bool according to JavaScript type conversions.
	Bool() bool

	// Str returns the object converted to string according to JavaScript type conversions. Does not implement fmt.Stringer on purpose.
	Str() string

	// Int returns the object converted to int according to JavaScript type conversions (parseInt).
	Int() int

	// Int64 returns the object converted to int64 according to JavaScript type conversions (parseInt).
	Int64() int64

	// Uint64 returns the object converted to uint64 according to JavaScript type conversions (parseInt).
	Uint64() uint64

	// Float returns the object converted to float64 according to JavaScript type conversions (parseFloat).
	Float() float64

	// Interface returns the object converted to interface{}. See GopherJS' README for details.
	Interface() interface{}

	// Unsafe returns the object as an uintptr, which can be converted via unsafe.Pointer. Not intended for public use.
	Unsafe() uintptr

	// IsUndefined returns true if the object is the JavaScript value "undefined".
	IsUndefined() bool

	// IsNull returns true if the object is the JavaScript value "null".
	IsNull() bool
}

// Error encapsulates JavaScript errors. Those are turned into a Go panic and may be rescued, giving an *Error that holds the JavaScript error object.
type Error struct {
	Object
}

// Error returns the message of the encapsulated JavaScript error object.
func (err *Error) Error() string {
	return "JavaScript error: " + err.Get("message").Str()
}

// Stack returns the stack property of the encapsulated JavaScript error object.
func (err *Error) Stack() string {
	return err.Get("stack").Str()
}

// Global gives JavaScript's global object ("window" for browsers and "GLOBAL" for Node.js). Set this to a mock for testing with pure Go.
var Global Object

// This gives the value of JavaScript's "this" keyword. It can be used when passing Go functions to JavaScript as callbacks. Set this to a mock for testing with pure Go.
var This Object

// Arguments gives the value of JavaScript's "arguments" keyword. It can be used when passing Go functions to JavaScript as callbacks. Set this to a mock for testing with pure Go.
var Arguments []Object

// Module gives the value of the "module" variable set by Node.js.
var Module Object

// Debugger gets compiled to JavaScript's "debugger;" statement.
func Debugger() {}

// InternalObject returns the internal JavaScript object that represents i. Not intended for public use.
func InternalObject(i interface{}) Object {
	return nil
}

// Keys returns the keys of the given JavaScript object.
func Keys(o Object) []string {
	if o.IsUndefined() || o.IsNull() {
		return nil
	}
	a := Global.Get("Object").Call("keys", o)
	s := make([]string, a.Length())
	for i := 0; i < a.Length(); i++ {
		s[i] = a.Index(i).Str()
	}
	return s
}

// M is a simple map type. It is intended as a shorthand for JavaScript objects (before conversion).
type M map[string]interface{}

// S is a simple slice type. It is intended as a shorthand for JavaScript arrays (before conversion).
type S []interface{}

func init() {
	// avoid dead code elimination of Error
	e := Error{}
	_ = e
}
<commit_msg>added hint to documentation of js.Module (fixes #132)<commit_after>// Package js provides functions for interacting with native JavaScript APIs. Calls to these functions are treated specially by GopherJS and translated directly to their JavaScript syntax.
//
// Type conversions between Go types and JavaScript types are performed automatically according to the following table:
//
//  | Go types                       | Go interface type              | JavaScript type |
//  | ------------------------------ | ------------------------------ | --------------- |
//  | bool                           | bool                           | Boolean         |
//  | int?, uint?, float?            | float64                        | Number          |
//  | string                         | string                         | String          |
//  | [?]int8                        | []int8                         | Int8Array       |
//  | [?]int16                       | []int16                        | Int16Array      |
//  | [?]int32, [?]int               | []int                          | Int32Array      |
//  | [?]uint8                       | []uint8                        | Int8Array       |
//  | [?]uint16                      | []uint16                       | Int16Array      |
//  | [?]uint32, [?]uint, [?]uintptr | []uint                         | Int32Array      |
//  | [?]float32                     | []float32                      | Float32Array    |
//  | [?]float64                     | []float64                      | Float64Array    |
//  | all other slices and arrays    | []interface{}                  | Array           |
//  | maps, structs                  | map[string]interface{}         | Object          |
//  | functions                      | func(...interface{}) js.Object | Function        |
//  | time.Time                      | time.Time                      | Date            |
//
// The second column denotes the types that are used when converting to `interface{}`. An exception are DOM elements, those are kept with the js.Object type. Additionally, a pointer to a named type is passed to JavaScript as an object which has wrappers for the type's exported methods. This can be used to provide getter and setter methods for Go fields to JavaScript.
package js

// Object is a container for a native JavaScript object. Calls to its methods are treated specially by GopherJS and translated directly to their JavaScript syntax.
type Object interface {

	// Get returns the object's property with the given key.
	Get(key string) Object

	// Set assigns the value to the object's property with the given key.
	Set(key string, value interface{})

	// Delete removes the object's property with the given key.
	Delete(key string)

	// Get returns the object's "length" property, converted to int.
	Length() int

	// Index returns the i'th element of an array.
	Index(i int) Object

	// SetIndex sets the i'th element of an array.
	SetIndex(i int, value interface{})

	// Call calls the object's method with the given name.
	Call(name string, args ...interface{}) Object

	// Invoke calls the object itself. This will fail if it is not a function.
	Invoke(args ...interface{}) Object

	// New creates a new instance of this type object. This will fail if it not a function (constructor).
	New(args ...interface{}) Object

	// Bool returns the object converted to bool according to JavaScript type conversions.
	Bool() bool

	// Str returns the object converted to string according to JavaScript type conversions. Does not implement fmt.Stringer on purpose.
	Str() string

	// Int returns the object converted to int according to JavaScript type conversions (parseInt).
	Int() int

	// Int64 returns the object converted to int64 according to JavaScript type conversions (parseInt).
	Int64() int64

	// Uint64 returns the object converted to uint64 according to JavaScript type conversions (parseInt).
	Uint64() uint64

	// Float returns the object converted to float64 according to JavaScript type conversions (parseFloat).
	Float() float64

	// Interface returns the object converted to interface{}. See GopherJS' README for details.
	Interface() interface{}

	// Unsafe returns the object as an uintptr, which can be converted via unsafe.Pointer. Not intended for public use.
	Unsafe() uintptr

	// IsUndefined returns true if the object is the JavaScript value "undefined".
	IsUndefined() bool

	// IsNull returns true if the object is the JavaScript value "null".
	IsNull() bool
}

// Error encapsulates JavaScript errors. Those are turned into a Go panic and may be rescued, giving an *Error that holds the JavaScript error object.
type Error struct {
	Object
}

// Error returns the message of the encapsulated JavaScript error object.
func (err *Error) Error() string {
	return "JavaScript error: " + err.Get("message").Str()
}

// Stack returns the stack property of the encapsulated JavaScript error object.
func (err *Error) Stack() string {
	return err.Get("stack").Str()
}

// Global gives JavaScript's global object ("window" for browsers and "GLOBAL" for Node.js). Set this to a mock for testing with pure Go.
var Global Object

// This gives the value of JavaScript's "this" keyword. It can be used when passing Go functions to JavaScript as callbacks. Set this to a mock for testing with pure Go.
var This Object

// Arguments gives the value of JavaScript's "arguments" keyword. It can be used when passing Go functions to JavaScript as callbacks. Set this to a mock for testing with pure Go.
var Arguments []Object

// Module gives the value of the "module" variable set by Node.js. Hint: Set a module export with 'js.Module.Get("exports").Set("exportName", ...)'.
var Module Object

// Debugger gets compiled to JavaScript's "debugger;" statement.
func Debugger() {}

// InternalObject returns the internal JavaScript object that represents i. Not intended for public use.
func InternalObject(i interface{}) Object {
	return nil
}

// Keys returns the keys of the given JavaScript object.
func Keys(o Object) []string {
	if o.IsUndefined() || o.IsNull() {
		return nil
	}
	a := Global.Get("Object").Call("keys", o)
	s := make([]string, a.Length())
	for i := 0; i < a.Length(); i++ {
		s[i] = a.Index(i).Str()
	}
	return s
}

// M is a simple map type. It is intended as a shorthand for JavaScript objects (before conversion).
type M map[string]interface{}

// S is a simple slice type. It is intended as a shorthand for JavaScript arrays (before conversion).
type S []interface{}

func init() {
	// avoid dead code elimination of Error
	e := Error{}
	_ = e
}
<|endoftext|>


<commit_before>package tests

import (
	"bytes"
	"encoding/xml"
	"fmt"
	"io"
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	v1 "kubevirt.io/client-go/api/v1"
	"kubevirt.io/client-go/kubecli"
)

func ExpectMigrationSuccess(virtClient kubecli.KubevirtClient, migration *v1.VirtualMachineInstanceMigration, timeout int) string {
	By("Waiting until the Migration Completes")
	uid := ""
	Eventually(func() error {
		migration, err := virtClient.VirtualMachineInstanceMigration(migration.Namespace).Get(migration.Name, &metav1.GetOptions{})
		if err != nil {
			return err
		}

		Expect(migration.Status.Phase).ToNot(Equal(v1.MigrationFailed), "migration should not fail")

		uid = string(migration.UID)
		if migration.Status.Phase == v1.MigrationSucceeded {
			return nil
		}
		return fmt.Errorf("migration is in the phase: %s", migration.Status.Phase)

	}, timeout, 1*time.Second).ShouldNot(HaveOccurred(), fmt.Sprintf("migration should succeed after %d s", timeout))
	return uid
}

func RunMigrationAndExpectCompletion(virtClient kubecli.KubevirtClient, migration *v1.VirtualMachineInstanceMigration, timeout int) string {
	By("Starting a Migration")
	var err error
	var migrationCreated *v1.VirtualMachineInstanceMigration
	Eventually(func() error {
		migrationCreated, err = virtClient.VirtualMachineInstanceMigration(migration.Namespace).Create(migration)
		return err
	}, timeout, 1*time.Second).Should(Succeed(), "migration creation should succeed")
	migration = migrationCreated

	return ExpectMigrationSuccess(virtClient, migration, timeout)
}

func ConfirmVMIPostMigration(virtClient kubecli.KubevirtClient, vmi *v1.VirtualMachineInstance, migrationUID string) {
	By("Retrieving the VMI post migration")
	vmi, err := virtClient.VirtualMachineInstance(vmi.Namespace).Get(vmi.Name, &metav1.GetOptions{})
	Expect(err).ToNot(HaveOccurred(), "should have been able to retrive the VMI instance")

	By("Verifying the VMI's migration state")
	Expect(vmi.Status.MigrationState).ToNot(BeNil(), "should have been able to retrieve the VMIs `Status::MigrationState`")
	Expect(vmi.Status.MigrationState.StartTimestamp).ToNot(BeNil(), "the VMIs `Status::MigrationState` should have a StartTimestamp")
	Expect(vmi.Status.MigrationState.EndTimestamp).ToNot(BeNil(), "the VMIs `Status::MigrationState` should have a EndTimestamp")
	Expect(vmi.Status.MigrationState.TargetNode).To(Equal(vmi.Status.NodeName), "the VMI should have migrated to the desired node")
	Expect(vmi.Status.MigrationState.TargetNode).NotTo(Equal(vmi.Status.MigrationState.SourceNode), "the VMI must have migrated to a different node from the one it originated from")
	Expect(vmi.Status.MigrationState.Completed).To(BeTrue(), "the VMI migration state must have completed")
	Expect(vmi.Status.MigrationState.Failed).To(BeFalse(), "the VMI migration status must not have failed")
	Expect(vmi.Status.MigrationState.TargetNodeAddress).NotTo(Equal(""), "the VMI `Status::MigrationState::TargetNodeAddress` must not be empty")
	Expect(string(vmi.Status.MigrationState.MigrationUID)).To(Equal(migrationUID), "the VMI migration UID must be the expected one")

	By("Verifying the VMI's is in the running state")
	Expect(vmi.Status.Phase).To(Equal(v1.Running), "the VMI must be in `Running` state after the migration")
}

func EnsureNoMigrationMetadataInPersistentXML(vmi *v1.VirtualMachineInstance) {
	domXML := RunCommandOnVmiPod(vmi, []string{"virsh", "dumpxml", "1"})
	decoder := xml.NewDecoder(bytes.NewReader([]byte(domXML)))

	var location = make([]string, 0)
	var found = false
	for {
		token, err := decoder.RawToken()
		if err == io.EOF {
			break
		}
		Expect(err).To(BeNil(), "error getting token: %v\n", err)

		switch v := token.(type) {
		case xml.StartElement:
			location = append(location, v.Name.Local)

			if len(location) >= 4 &&
				location[0] == "domain" &&
				location[1] == "metadata" &&
				location[2] == "kubevirt" &&
				location[3] == "migration" {
				found = true
			}
			Expect(found).To(BeFalse(), "Unexpected KubeVirt migration metadata found in domain XML")
		case xml.EndElement:
			location = location[:len(location)-1]
		}

	}
}
<commit_msg>Use offset in ExpectMigrationSuccess<commit_after>package tests

import (
	"bytes"
	"encoding/xml"
	"fmt"
	"io"
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	v1 "kubevirt.io/client-go/api/v1"
	"kubevirt.io/client-go/kubecli"
)

func ExpectMigrationSuccess(virtClient kubecli.KubevirtClient, migration *v1.VirtualMachineInstanceMigration, timeout int) string {
	return expectMigrationSuccessWithOffset(2, virtClient, migration, timeout)
}

func expectMigrationSuccessWithOffset(offset int, virtClient kubecli.KubevirtClient, migration *v1.VirtualMachineInstanceMigration, timeout int) string {
	By("Waiting until the Migration Completes")
	uid := ""
	EventuallyWithOffset(offset, func() error {
		migration, err := virtClient.VirtualMachineInstanceMigration(migration.Namespace).Get(migration.Name, &metav1.GetOptions{})
		if err != nil {
			return err
		}

		ExpectWithOffset(offset+1, migration.Status.Phase).ToNot(Equal(v1.MigrationFailed), "migration should not fail")

		uid = string(migration.UID)
		if migration.Status.Phase == v1.MigrationSucceeded {
			return nil
		}
		return fmt.Errorf("migration is in the phase: %s", migration.Status.Phase)

	}, timeout, 1*time.Second).ShouldNot(HaveOccurred(), fmt.Sprintf("migration should succeed after %d s", timeout))
	return uid
}

func RunMigrationAndExpectCompletion(virtClient kubecli.KubevirtClient, migration *v1.VirtualMachineInstanceMigration, timeout int) string {
	By("Starting a Migration")
	var err error
	var migrationCreated *v1.VirtualMachineInstanceMigration
	Eventually(func() error {
		migrationCreated, err = virtClient.VirtualMachineInstanceMigration(migration.Namespace).Create(migration)
		return err
	}, timeout, 1*time.Second).Should(Succeed(), "migration creation should succeed")
	migration = migrationCreated

	return ExpectMigrationSuccess(virtClient, migration, timeout)
}

func ConfirmVMIPostMigration(virtClient kubecli.KubevirtClient, vmi *v1.VirtualMachineInstance, migrationUID string) {
	By("Retrieving the VMI post migration")
	vmi, err := virtClient.VirtualMachineInstance(vmi.Namespace).Get(vmi.Name, &metav1.GetOptions{})
	Expect(err).ToNot(HaveOccurred(), "should have been able to retrive the VMI instance")

	By("Verifying the VMI's migration state")
	Expect(vmi.Status.MigrationState).ToNot(BeNil(), "should have been able to retrieve the VMIs `Status::MigrationState`")
	Expect(vmi.Status.MigrationState.StartTimestamp).ToNot(BeNil(), "the VMIs `Status::MigrationState` should have a StartTimestamp")
	Expect(vmi.Status.MigrationState.EndTimestamp).ToNot(BeNil(), "the VMIs `Status::MigrationState` should have a EndTimestamp")
	Expect(vmi.Status.MigrationState.TargetNode).To(Equal(vmi.Status.NodeName), "the VMI should have migrated to the desired node")
	Expect(vmi.Status.MigrationState.TargetNode).NotTo(Equal(vmi.Status.MigrationState.SourceNode), "the VMI must have migrated to a different node from the one it originated from")
	Expect(vmi.Status.MigrationState.Completed).To(BeTrue(), "the VMI migration state must have completed")
	Expect(vmi.Status.MigrationState.Failed).To(BeFalse(), "the VMI migration status must not have failed")
	Expect(vmi.Status.MigrationState.TargetNodeAddress).NotTo(Equal(""), "the VMI `Status::MigrationState::TargetNodeAddress` must not be empty")
	Expect(string(vmi.Status.MigrationState.MigrationUID)).To(Equal(migrationUID), "the VMI migration UID must be the expected one")

	By("Verifying the VMI's is in the running state")
	Expect(vmi.Status.Phase).To(Equal(v1.Running), "the VMI must be in `Running` state after the migration")
}

func EnsureNoMigrationMetadataInPersistentXML(vmi *v1.VirtualMachineInstance) {
	domXML := RunCommandOnVmiPod(vmi, []string{"virsh", "dumpxml", "1"})
	decoder := xml.NewDecoder(bytes.NewReader([]byte(domXML)))

	var location = make([]string, 0)
	var found = false
	for {
		token, err := decoder.RawToken()
		if err == io.EOF {
			break
		}
		Expect(err).To(BeNil(), "error getting token: %v\n", err)

		switch v := token.(type) {
		case xml.StartElement:
			location = append(location, v.Name.Local)

			if len(location) >= 4 &&
				location[0] == "domain" &&
				location[1] == "metadata" &&
				location[2] == "kubevirt" &&
				location[3] == "migration" {
				found = true
			}
			Expect(found).To(BeFalse(), "Unexpected KubeVirt migration metadata found in domain XML")
		case xml.EndElement:
			location = location[:len(location)-1]
		}

	}
}
<|endoftext|>


<commit_before>package main

import(
  "testing"
  "strings"
)

func fixtureCmd() string { return "exit" }
func fixtureArgs() []string { return []string { "0" } }
func fixtureBadArgs() []string { return []string { "1" } }

func fixtureCmdSlice(args []string) []string {
  return append( []string { fixtureCmd() }, args...)
}

func fixtureCmdString(args []string) string {
  return strings.Join(fixtureCmdSlice(args), " ")
}

func TestBuildArgs(t *testing.T) {
  args := fixtureArgs()
  cmd := fixtureCmdSlice(args)
  str := buildArgs(cmd)
  cmd_str := fixtureCmdString(args)
  if str != cmd_str {
    t.Fatalf("%s should be %s", str, cmd_str)
  }
}

func TestRunSuccessfully(t *testing.T) {
  ok := run(fixtureCmdSlice(fixtureArgs()))
  if ok != 0 {
    t.Fatalf("%s should be 0", ok)
  }
}

func TestRunExit(t *testing.T) {
  err := run(fixtureCmdSlice(fixtureBadArgs()))
  if err != 1 {
    t.Fatalf("%s should not be 1", err)
  }
}
<commit_msg>Close #9. Add benchmark for run.<commit_after>package main

import(
  "testing"
  "strings"
)

func fixtureCmd() string { return "exit" }
func fixtureArgs() []string { return []string { "0" } }
func fixtureBadArgs() []string { return []string { "1" } }

func fixtureCmdSlice(args []string) []string {
  return append( []string { fixtureCmd() }, args...)
}

func fixtureCmdString(args []string) string {
  return strings.Join(fixtureCmdSlice(args), " ")
}

func TestBuildArgs(t *testing.T) {
  args := fixtureArgs()
  cmd := fixtureCmdSlice(args)
  str := buildArgs(cmd)
  cmd_str := fixtureCmdString(args)
  if str != cmd_str {
    t.Fatalf("%s should be %s", str, cmd_str)
  }
}

func TestRunSuccessfully(t *testing.T) {
  ok := run(fixtureCmdSlice(fixtureArgs()))
  if ok != 0 {
    t.Fatalf("%s should be 0", ok)
  }
}

func TestRunExit(t *testing.T) {
  err := run(fixtureCmdSlice(fixtureBadArgs()))
  if err != 1 {
    t.Fatalf("%s should not be 1", err)
  }
}

func BenchmarkRunSuccessfully(b *testing.B) {
  for n := 0; n < b.N; n++ {
    run(fixtureCmdSlice(fixtureArgs()))
  }
}

func BenchmarkRunExit(b *testing.B) {
  for n := 0; n < b.N; n++ {
    run(fixtureCmdSlice(fixtureBadArgs()))
  }
}
<|endoftext|>


<commit_before>package bunq

import (
	"encoding/json"
	"fmt"
	"io"
)

// Error represents an error returned by the bunq API.
type Error struct {
	ErrorDescription           string
	ErrorDescriptionTranslated string
}

// Errors is an array of Error structs.
type Errors []Error

func (e Errors) Error() string {
	var errs []string
	for i := range e {
		errs = append(errs, e[i].ErrorDescription)
	}

	return fmt.Sprintf("%v", errs)
}

func decodeError(r io.Reader) error {
	var apiError struct {
		Error []struct {
			ErrorDescription           string `json:"error_description"`
			ErrorDescriptionTranslated string `json:"error_description_translated"`
		} `json:"Error"`
	}
	err := json.NewDecoder(r).Decode(&apiError)
	if err != nil {
		return fmt.Errorf("bunq: could not decode errors from json: %v", err)
	}

	var errors Errors
	for i := range apiError.Error {
		errors = append(errors, Error{
			ErrorDescription:           apiError.Error[i].ErrorDescription,
			ErrorDescriptionTranslated: apiError.Error[i].ErrorDescriptionTranslated,
		})
	}

	return errors
}
<commit_msg>Improve error decoding/output<commit_after>package bunq

import (
	"encoding/json"
	"fmt"
	"io"
	"strings"
)

// Error represents an error returned by the bunq API.
type Error struct {
	ErrorDescription           string
	ErrorDescriptionTranslated string
}

// Errors is an array of Error structs.
type Errors []Error

func (e Errors) Error() string {
	errs := make([]string, len(e))
	for i, err := range e {
		errs[i] = err.ErrorDescription
	}

	return strings.Join(errs, ", ")
}

func decodeError(r io.Reader) error {
	var apiError struct {
		Error []struct {
			ErrorDescription           string `json:"error_description"`
			ErrorDescriptionTranslated string `json:"error_description_translated"`
		} `json:"Error"`
	}
	err := json.NewDecoder(r).Decode(&apiError)
	if err != nil {
		return fmt.Errorf("could not decode errors from json: %v", err)
	}

	var errors Errors
	for i := range apiError.Error {
		errors = append(errors, Error{
			ErrorDescription:           apiError.Error[i].ErrorDescription,
			ErrorDescriptionTranslated: apiError.Error[i].ErrorDescriptionTranslated,
		})
	}

	return errors
}
<|endoftext|>


<commit_before>// http server with socket.io
package tailbridge

import (
    "net/http"
    "strconv"
    "github.com/googollee/go-socket.io"
    "os/exec"
    "log"
    "strings"
    "bytes"
)

func Tail(machine string, user string, port int, file_name string, out_bytes chan string) {
    tail_cmd := "tail -f " + file_name
    cmd := exec.Command(
        "ssh", "-p", strconv.Itoa(port),
        user + "@" + machine,
        tail_cmd)

    stdout, err := cmd.StdoutPipe()

    if err != nil {
      log.Fatal(err)
    }

    cmd.Start()
    defer cmd.Wait()

    line := bytes.NewBuffer([]byte{})
    r := make([]byte, 1)

    for {
        stdout.Read(r)

        if r[0] == '\n' {
            out_bytes <- line.String()
            line.Reset()
        } else {
            line.WriteByte(r[0])
        }
    }
}

func InitServer(port int) {
    sio_server, err := socketio.NewServer(nil)

    if err != nil {
        log.Fatal(err)
    }

    sio_server.On("connection", func(socket socketio.Socket) {
        log.Println("Got new connection")

        socket.On("init", func(msg string) {
            msg_parts := strings.Split(msg, ",")
            if len(msg_parts) < 2 {
                println("Insufficient data received from client.")
                return
            }

            user, port, ok := GetMachineParams(msg_parts[0])

            if !ok {
                println("Some problem with the IP provided.")
            }

            out_bytes := make(chan string)
            go Tail(msg_parts[0], user, port, msg_parts[1], out_bytes)

            for {
                socket.Emit("stream", string(<-out_bytes))
            }
        })

        socket.On("disconnection", func() {
            log.Println("on disconnect")
        })
    })

    sio_server.On("error", func(so socketio.Socket, err error) {
        log.Println("error:", err)
    })

    http.Handle("/socket.io/", sio_server)
    http.Handle("/", http.FileServer(http.Dir("./static")))

    port_str := strconv.Itoa(port)
    log.Println("Listening on 0.0.0.0:" + port_str)
    log.Fatal(http.ListenAndServe("0.0.0.0:" + port_str, nil))
}
<commit_msg>no strict host checking<commit_after>// http server with socket.io
package tailbridge

import (
    "net/http"
    "strconv"
    "github.com/googollee/go-socket.io"
    "os/exec"
    "log"
    "strings"
    "bytes"
)

func Tail(machine string, user string, port int, file_name string, out_bytes chan string) {
    tail_cmd := "tail -f " + file_name
    cmd := exec.Command(
        "ssh", "-oStrictHostKeyChecking=no", "-oUserKnownHostsFile=/dev/null",
        "-p", strconv.Itoa(port),
        user + "@" + machine,
        tail_cmd)

    stdout, err := cmd.StdoutPipe()

    if err != nil {
      log.Fatal(err)
    }

    cmd.Start()
    defer cmd.Wait()

    line := bytes.NewBuffer([]byte{})
    r := make([]byte, 1)

    for {
        stdout.Read(r)

        if r[0] == '\n' {
            out_bytes <- line.String()
            line.Reset()
        } else {
            line.WriteByte(r[0])
        }
    }
}

func InitServer(port int) {
    sio_server, err := socketio.NewServer(nil)

    if err != nil {
        log.Fatal(err)
    }

    sio_server.On("connection", func(socket socketio.Socket) {
        log.Println("Got new connection")

        socket.On("init", func(msg string) {
            msg_parts := strings.Split(msg, ",")
            if len(msg_parts) < 2 {
                println("Insufficient data received from client.")
                return
            }

            user, port, ok := GetMachineParams(msg_parts[0])

            if !ok {
                println("Some problem with the IP provided.")
            }

            out_bytes := make(chan string)
            go Tail(msg_parts[0], user, port, msg_parts[1], out_bytes)

            for {
                socket.Emit("stream", string(<-out_bytes))
            }
        })

        socket.On("disconnection", func() {
            log.Println("on disconnect")
        })
    })

    sio_server.On("error", func(so socketio.Socket, err error) {
        log.Println("error:", err)
    })

    http.Handle("/socket.io/", sio_server)
    http.Handle("/", http.FileServer(http.Dir("./static")))

    port_str := strconv.Itoa(port)
    log.Println("Listening on 0.0.0.0:" + port_str)
    log.Fatal(http.ListenAndServe("0.0.0.0:" + port_str, nil))
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"net/mail"
	"strings"
	"sync"
	"time"

	"github.com/awslabs/aws-sdk-go/aws"
	"github.com/awslabs/aws-sdk-go/gen/ec2"
	. "github.com/tj/go-debug"
)

var (
	debugAWS = Debug("reaper:aws")
	debugAll = Debug("reaper:aws:AllInstances")
)

type FilterFunc func(*Instance) bool

type StateEnum int

const (
	STATE_START StateEnum = iota
	STATE_NOTIFY1
	STATE_NOTIFY2
	STATE_IGNORE
)

func (s StateEnum) String() string {
	switch s {
	case STATE_NOTIFY1:
		return "notify1"
	case STATE_NOTIFY2:
		return "notify2"
	case STATE_IGNORE:
		return "ignore"
	default:
		return "start"
	}
}

const (
	REAPER_TAG = "REAPER"
	S_SEP      = "|"
	S_TFORMAT  = "2006-01-02 03:04PM MST"
)

type State struct {
	State StateEnum

	// State must be maintained until this time
	Until time.Time
}

func (s *State) Visible() bool { return time.Now().After(s.Until) }
func (s *State) String() string {
	return s.State.String() + S_SEP + s.Until.Format(S_TFORMAT)
}

type Instances []*Instance
type Instance struct {
	id         string
	region     string
	state      string
	launchTime time.Time

	tags map[string]string

	// reaper state
	reaper *State
}

func NewInstance(region string, instance *ec2.Instance) *Instance {

	// ughhhhhh pointers to strings suck
	_id := "nil"
	_state := "nil"

	if instance.InstanceID != nil {
		_id = *instance.InstanceID
	}

	if instance.State != nil {
		if instance.State.Name != nil {
			_state = *instance.State.Name
		}
	}

	i := Instance{
		id:         _id,
		region:     region, // passed in cause not possible to extract out of api
		state:      _state,
		launchTime: instance.LaunchTime,
		tags:       make(map[string]string),
	}

	for _, tag := range instance.Tags {
		i.tags[*tag.Key] = *tag.Value
	}

	i.reaper = ParseState(i.tags[REAPER_TAG])

	return &i
}

func (i *Instance) Tagged(tag string) (ok bool) {
	_, ok = i.tags[tag]
	return
}

func (i *Instance) Id() string            { return i.id }
func (i *Instance) Region() string        { return i.region }
func (i *Instance) State() string         { return i.state }
func (i *Instance) LaunchTime() time.Time { return i.launchTime }
func (i *Instance) Reaper() *State        { return i.reaper }

// Name extracts the "Name" tag
func (i *Instance) Name() string { return i.tags["Name"] }

// Owned checks if the instance has an Owner tag
func (i *Instance) Owned() (ok bool) { return i.Tagged("Owner") }

// Owner extracts useful information out of the Owner tag which should
// be parsable by mail.ParseAddress
func (i *Instance) Owner() *mail.Address {
	if addr, err := mail.ParseAddress(i.Tag("Owner")); err == nil {
		return addr
	}

	return nil
}

// Tag returns the tag's value or an empty string if it does not exist
func (i *Instance) Tag(t string) string { return i.tags[t] }

// Autoscaled checks if the instance is part of an autoscaling group
func (i *Instance) AutoScaled() (ok bool) { return i.Tagged("aws:autoscaling:groupName") }

func UpdateReaperState(creds aws.CredentialsProvider, region, instanceId string, newState *State) error {
	debugAWS("UpdateReaperState region:%s instance: %s", region, instanceId)
	req := &ec2.CreateTagsRequest{
		DryRun:    aws.False(),
		Resources: []string{instanceId},
		Tags: []ec2.Tag{
			ec2.Tag{
				Key:   aws.String(REAPER_TAG),
				Value: aws.String(newState.String()),
			},
		},
	}

	api := ec2.New(creds, region, nil)
	return api.CreateTags(req)
}

func Terminate(creds aws.CredentialsProvider, region, instanceId string) error {
	api := ec2.New(creds, region, nil)
	req := &ec2.TerminateInstancesRequest{
		InstanceIDs: []string{instanceId},
	}

	resp, err := api.TerminateInstances(req)

	if err != nil {
		return err
	}

	if len(resp.TerminatingInstances) != 1 {
		return fmt.Errorf("Instance could not be terminated")
	}

	return nil
}

func ParseState(state string) (defaultState *State) {

	defaultState = &State{STATE_START, time.Time{}}

	if state == "" {
		return
	}

	s := strings.Split(state, S_SEP)

	if len(s) != 2 {
		return
	}

	var stateEnum StateEnum
	switch s[0] {
	case "start":
		stateEnum = STATE_START
	case "notify1":
		stateEnum = STATE_NOTIFY1
	case "notify2":
		stateEnum = STATE_NOTIFY2
	case "ignore":
		stateEnum = STATE_IGNORE
	default:
		return
	}

	t, err := time.Parse(S_TFORMAT, s[1])
	if err != nil {
		return
	}

	return &State{stateEnum, t}
}

// Filter creates a new list of Instances that match the filter
func (i Instances) Filter(f FilterFunc) (newList Instances) {
	for _, i := range i {
		if f(i) {
			newList = append(newList, i)
		}
	}

	return
}

// AllInstances fetches in parallel all instances in the provided endpoints
func AllInstances(endpoints EndpointMap) Instances {

	var wg sync.WaitGroup
	in := make(chan *Instance)

	// fetch all info in parallel
	for region, api := range endpoints {
		debugAll("DescribeInstances in %s", region)
		wg.Add(1)
		go func(region string, api *ec2.EC2) {
			defer wg.Done()

			resp, err := api.DescribeInstances(nil)
			if err != nil {
				// probably should do something here...
				return
			}

			sum := 0
			for _, r := range resp.Reservations {
				for _, instance := range r.Instances {
					sum += 1
					in <- NewInstance(region, &instance)
				}
			}

			debugAll("Found %d instances in %s", sum, region)

		}(region, api)
	}

	var list Instances
	done := make(chan struct{})

	// build up the list
	go func() {
		for i := range in {
			list = append(list, i)
		}
		done <- struct{}{}
	}()

	// wait for all the fetches to finish publishing
	wg.Wait()
	close(in)

	// wait for appending goroutine to be done
	<-done

	return list
}
<commit_msg>reduce exposure for reaper constants<commit_after>package aws

import (
	"fmt"
	"net/mail"
	"strings"
	"sync"
	"time"

	"github.com/awslabs/aws-sdk-go/aws"
	"github.com/awslabs/aws-sdk-go/gen/ec2"
	. "github.com/tj/go-debug"
)

var (
	debugAWS = Debug("reaper:aws")
	debugAll = Debug("reaper:aws:AllInstances")
)

type FilterFunc func(*Instance) bool

type StateEnum int

const (
	STATE_START StateEnum = iota
	STATE_NOTIFY1
	STATE_NOTIFY2
	STATE_IGNORE
)

func (s StateEnum) String() string {
	switch s {
	case STATE_NOTIFY1:
		return "notify1"
	case STATE_NOTIFY2:
		return "notify2"
	case STATE_IGNORE:
		return "ignore"
	default:
		return "start"
	}
}

const (
	reaper_tag = "REAPER"
	s_sep      = "|"
	s_tformat  = "2006-01-02 03:04PM MST"
)

type State struct {
	State StateEnum

	// State must be maintained until this time
	Until time.Time
}

func (s *State) Visible() bool { return time.Now().After(s.Until) }
func (s *State) String() string {
	return s.State.String() + s_sep + s.Until.Format(s_tformat)
}

type Instances []*Instance
type Instance struct {
	id         string
	region     string
	state      string
	launchTime time.Time

	tags map[string]string

	// reaper state
	reaper *State
}

func NewInstance(region string, instance *ec2.Instance) *Instance {

	// ughhhhhh pointers to strings suck
	_id := "nil"
	_state := "nil"

	if instance.InstanceID != nil {
		_id = *instance.InstanceID
	}

	if instance.State != nil {
		if instance.State.Name != nil {
			_state = *instance.State.Name
		}
	}

	i := Instance{
		id:         _id,
		region:     region, // passed in cause not possible to extract out of api
		state:      _state,
		launchTime: instance.LaunchTime,
		tags:       make(map[string]string),
	}

	for _, tag := range instance.Tags {
		i.tags[*tag.Key] = *tag.Value
	}

	i.reaper = ParseState(i.tags[reaper_tag])

	return &i
}

func (i *Instance) Tagged(tag string) (ok bool) {
	_, ok = i.tags[tag]
	return
}

func (i *Instance) Id() string            { return i.id }
func (i *Instance) Region() string        { return i.region }
func (i *Instance) State() string         { return i.state }
func (i *Instance) LaunchTime() time.Time { return i.launchTime }
func (i *Instance) Reaper() *State        { return i.reaper }

// Name extracts the "Name" tag
func (i *Instance) Name() string { return i.tags["Name"] }

// Owned checks if the instance has an Owner tag
func (i *Instance) Owned() (ok bool) { return i.Tagged("Owner") }

// Owner extracts useful information out of the Owner tag which should
// be parsable by mail.ParseAddress
func (i *Instance) Owner() *mail.Address {
	if addr, err := mail.ParseAddress(i.Tag("Owner")); err == nil {
		return addr
	}

	return nil
}

// Tag returns the tag's value or an empty string if it does not exist
func (i *Instance) Tag(t string) string { return i.tags[t] }

// Autoscaled checks if the instance is part of an autoscaling group
func (i *Instance) AutoScaled() (ok bool) { return i.Tagged("aws:autoscaling:groupName") }

func UpdateReaperState(creds aws.CredentialsProvider, region, instanceId string, newState *State) error {
	debugAWS("UpdateReaperState region:%s instance: %s", region, instanceId)
	req := &ec2.CreateTagsRequest{
		DryRun:    aws.False(),
		Resources: []string{instanceId},
		Tags: []ec2.Tag{
			ec2.Tag{
				Key:   aws.String(reaper_tag),
				Value: aws.String(newState.String()),
			},
		},
	}

	api := ec2.New(creds, region, nil)
	return api.CreateTags(req)
}

func Terminate(creds aws.CredentialsProvider, region, instanceId string) error {
	api := ec2.New(creds, region, nil)
	req := &ec2.TerminateInstancesRequest{
		InstanceIDs: []string{instanceId},
	}

	resp, err := api.TerminateInstances(req)

	if err != nil {
		return err
	}

	if len(resp.TerminatingInstances) != 1 {
		return fmt.Errorf("Instance could not be terminated")
	}

	return nil
}

func ParseState(state string) (defaultState *State) {

	defaultState = &State{STATE_START, time.Time{}}

	if state == "" {
		return
	}

	s := strings.Split(state, s_sep)

	if len(s) != 2 {
		return
	}

	var stateEnum StateEnum
	switch s[0] {
	case "start":
		stateEnum = STATE_START
	case "notify1":
		stateEnum = STATE_NOTIFY1
	case "notify2":
		stateEnum = STATE_NOTIFY2
	case "ignore":
		stateEnum = STATE_IGNORE
	default:
		return
	}

	t, err := time.Parse(s_tformat, s[1])
	if err != nil {
		return
	}

	return &State{stateEnum, t}
}

// Filter creates a new list of Instances that match the filter
func (i Instances) Filter(f FilterFunc) (newList Instances) {
	for _, i := range i {
		if f(i) {
			newList = append(newList, i)
		}
	}

	return
}

// AllInstances fetches in parallel all instances in the provided endpoints
func AllInstances(endpoints EndpointMap) Instances {

	var wg sync.WaitGroup
	in := make(chan *Instance)

	// fetch all info in parallel
	for region, api := range endpoints {
		debugAll("DescribeInstances in %s", region)
		wg.Add(1)
		go func(region string, api *ec2.EC2) {
			defer wg.Done()

			resp, err := api.DescribeInstances(nil)
			if err != nil {
				// probably should do something here...
				return
			}

			sum := 0
			for _, r := range resp.Reservations {
				for _, instance := range r.Instances {
					sum += 1
					in <- NewInstance(region, &instance)
				}
			}

			debugAll("Found %d instances in %s", sum, region)

		}(region, api)
	}

	var list Instances
	done := make(chan struct{})

	// build up the list
	go func() {
		for i := range in {
			list = append(list, i)
		}
		done <- struct{}{}
	}()

	// wait for all the fetches to finish publishing
	wg.Wait()
	close(in)

	// wait for appending goroutine to be done
	<-done

	return list
}
<|endoftext|>