<commit_before>// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// The /doc/codewalk/ tree is synthesized from codewalk descriptions,
// files named $GOROOT/doc/codewalk/*.xml.
// For an example and a description of the format, see
// http://golang.org/doc/codewalk/codewalk or run godoc -http=:6060
// and see http://localhost:6060/doc/codewalk/codewalk .
// That page is itself a codewalk; the source code for it is
// $GOROOT/doc/codewalk/codewalk.xml.

package main

import (
	"log"
	"net/http"
	"regexp"
	"text/template"

	"code.google.com/p/go.tools/godoc"
	"code.google.com/p/go.tools/godoc/vfs"
)

var (
	pres *godoc.Presentation
	fs   = vfs.NameSpace{}
)

func registerHandlers(pres *godoc.Presentation) {
	if pres == nil {
		panic("nil Presentation")
	}
	http.HandleFunc("/doc/codewalk/", codewalk)
	http.Handle("/doc/play/", pres.FileServer())
	http.Handle("/robots.txt", pres.FileServer())
	http.Handle("/", pres)
	handlePathRedirects(pkgRedirects, "/pkg/")
	handlePathRedirects(cmdRedirects, "/cmd/")
	for prefix, redirect := range prefixHelpers {
		p := "/" + prefix + "/"
		h := makePrefixRedirectHandler(p, redirect)
		http.HandleFunc(p, h)
	}
	for path, redirect := range redirects {
		h := makeRedirectHandler(redirect)
		http.HandleFunc(path, h)
	}
}

func readTemplate(name string) *template.Template {
	if pres == nil {
		panic("no global Presentation set yet")
	}
	path := "lib/godoc/" + name

	// use underlying file system fs to read the template file
	// (cannot use template ParseFile functions directly)
	data, err := vfs.ReadFile(fs, path)
	if err != nil {
		log.Fatal("readTemplate: ", err)
	}
	// be explicit with errors (for app engine use)
	t, err := template.New(name).Funcs(pres.FuncMap()).Parse(string(data))
	if err != nil {
		log.Fatal("readTemplate: ", err)
	}
	return t
}

func readTemplates(p *godoc.Presentation, html bool) {
	p.PackageText = readTemplate("package.txt")
	p.SearchText = readTemplate("search.txt")

	if html {
		codewalkHTML = readTemplate("codewalk.html")
		codewalkdirHTML = readTemplate("codewalkdir.html")
		p.DirlistHTML = readTemplate("dirlist.html")
		p.ErrorHTML = readTemplate("error.html")
		p.ExampleHTML = readTemplate("example.html")
		p.GodocHTML = readTemplate("godoc.html")
		p.PackageHTML = readTemplate("package.html")
		p.SearchHTML = readTemplate("search.html")
		p.SearchDescXML = readTemplate("opensearch.xml")
	}
}

// Packages that were renamed between r60 and go1.
var pkgRedirects = map[string]string{
	"asn1":              "encoding/asn1",
	"big":               "math/big",
	"cmath":             "math/cmplx",
	"csv":               "encoding/csv",
	"exec":              "os/exec",
	"exp/template/html": "html/template",
	"gob":               "encoding/gob",
	"http":              "net/http",
	"http/cgi":          "net/http/cgi",
	"http/fcgi":         "net/http/fcgi",
	"http/httptest":     "net/http/httptest",
	"http/pprof":        "net/http/pprof",
	"json":              "encoding/json",
	"mail":              "net/mail",
	"rand":              "math/rand",
	"rpc":               "net/rpc",
	"rpc/jsonrpc":       "net/rpc/jsonrpc",
	"scanner":           "text/scanner",
	"smtp":              "net/smtp",
	"tabwriter":         "text/tabwriter",
	"template":          "text/template",
	"template/parse":    "text/template/parse",
	"url":               "net/url",
	"utf16":             "unicode/utf16",
	"utf8":              "unicode/utf8",
	"xml":               "encoding/xml",
}

// Commands that were renamed between r60 and go1.
var cmdRedirects = map[string]string{
	"gofix":     "fix",
	"goinstall": "go",
	"gopack":    "pack",
	"govet":     "vet",
	"goyacc":    "yacc",
}

var redirects = map[string]string{
	"/blog":      "http://blog.golang.org",
	"/build":     "http://build.golang.org",
	"/change":    "https://code.google.com/p/go/source/list",
	"/cl":        "https://gocodereview.appspot.com/",
	"/issue":     "https://code.google.com/p/go/issues",
	"/issue/new": "https://code.google.com/p/go/issues/entry",
	"/issues":    "https://code.google.com/p/go/issues",
	"/play":      "http://play.golang.org",
	"/ref":       "/doc/#references",
	"/ref/":      "/doc/#references",
	"/ref/mem":   "/doc/mem",
	"/ref/spec":  "/doc/spec",
	"/talks":     "http://talks.golang.org",
	"/tour":      "http://tour.golang.org",
	"/wiki":      "https://code.google.com/p/go-wiki/w/list",

	"/doc/articles/c_go_cgo.html":                    "/blog/c-go-cgo",
	"/doc/articles/concurrency_patterns.html":        "/blog/go-concurrency-patterns-timing-out-and",
	"/doc/articles/defer_panic_recover.html":         "/blog/defer-panic-and-recover",
	"/doc/articles/error_handling.html":              "/blog/error-handling-and-go",
	"/doc/articles/gobs_of_data.html":                "/blog/gobs-of-data",
	"/doc/articles/godoc_documenting_go_code.html":   "/blog/godoc-documenting-go-code",
	"/doc/articles/gos_declaration_syntax.html":      "/blog/gos-declaration-syntax",
	"/doc/articles/image_draw.html":                  "/blog/go-imagedraw-package",
	"/doc/articles/image_package.html":               "/blog/go-image-package",
	"/doc/articles/json_and_go.html":                 "/blog/json-and-go",
	"/doc/articles/json_rpc_tale_of_interfaces.html": "/blog/json-rpc-tale-of-interfaces",
	"/doc/articles/laws_of_reflection.html":          "/blog/laws-of-reflection",
	"/doc/articles/race_detector.html":               "/blog/race-detector",
	"/doc/articles/slices_usage_and_internals.html":  "/blog/go-slices-usage-and-internals",
	"/doc/go_for_cpp_programmers.html":               "https://code.google.com/p/go-wiki/wiki/GoForCPPProgrammers",
	"/doc/go_tutorial.html":                          "http://tour.golang.org/",
}

var prefixHelpers = map[string]string{
	"blog":   "http://blog.golang.org/",
	"change": "https://code.google.com/p/go/source/detail?r=",
	"cl":     "https://codereview.appspot.com/",
	"issue":  "https://code.google.com/p/go/issues/detail?id=",
	"play":   "http://play.golang.org/",
	"talks":  "http://talks.golang.org/",
	"wiki":   "https://code.google.com/p/go-wiki/wiki/",
}

func handlePathRedirects(redirects map[string]string, prefix string) {
	for source, target := range pkgRedirects {
		h := makeRedirectHandler(prefix + target + "/")
		p := prefix + source
		http.HandleFunc(p, h)
		http.HandleFunc(p+"/", h)
	}
}

func makeRedirectHandler(target string) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, target, http.StatusMovedPermanently)
	}
}

var validId = regexp.MustCompile(`^[A-Za-z0-9-]*$`)

func makePrefixRedirectHandler(prefix, baseURL string) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if p := r.URL.Path; p == prefix {
			// redirect /prefix/ to /prefix
			http.Redirect(w, r, p[:len(p)-1], http.StatusFound)
			return
		}
		id := r.URL.Path[len(prefix):]
		if !validId.MatchString(id) {
			http.Error(w, "Not found", http.StatusNotFound)
			return
		}
		target := baseURL + id
		http.Redirect(w, r, target, http.StatusFound)
	}
}
<commit_msg>go.tools/cmd/godoc: add redirects for godoc, vet, and gotest<commit_after>// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// The /doc/codewalk/ tree is synthesized from codewalk descriptions,
// files named $GOROOT/doc/codewalk/*.xml.
// For an example and a description of the format, see
// http://golang.org/doc/codewalk/codewalk or run godoc -http=:6060
// and see http://localhost:6060/doc/codewalk/codewalk .
// That page is itself a codewalk; the source code for it is
// $GOROOT/doc/codewalk/codewalk.xml.

package main

import (
	"log"
	"net/http"
	"regexp"
	"text/template"

	"code.google.com/p/go.tools/godoc"
	"code.google.com/p/go.tools/godoc/vfs"
)

var (
	pres *godoc.Presentation
	fs   = vfs.NameSpace{}
)

func registerHandlers(pres *godoc.Presentation) {
	if pres == nil {
		panic("nil Presentation")
	}
	http.HandleFunc("/doc/codewalk/", codewalk)
	http.Handle("/doc/play/", pres.FileServer())
	http.Handle("/robots.txt", pres.FileServer())
	http.Handle("/", pres)
	handlePathRedirects(pkgRedirects, "/pkg/")
	handlePathRedirects(cmdRedirects, "/cmd/")
	for prefix, redirect := range prefixHelpers {
		p := "/" + prefix + "/"
		h := makePrefixRedirectHandler(p, redirect)
		http.HandleFunc(p, h)
	}
	for path, redirect := range redirects {
		h := makeRedirectHandler(redirect)
		http.HandleFunc(path, h)
	}
}

func readTemplate(name string) *template.Template {
	if pres == nil {
		panic("no global Presentation set yet")
	}
	path := "lib/godoc/" + name

	// use underlying file system fs to read the template file
	// (cannot use template ParseFile functions directly)
	data, err := vfs.ReadFile(fs, path)
	if err != nil {
		log.Fatal("readTemplate: ", err)
	}
	// be explicit with errors (for app engine use)
	t, err := template.New(name).Funcs(pres.FuncMap()).Parse(string(data))
	if err != nil {
		log.Fatal("readTemplate: ", err)
	}
	return t
}

func readTemplates(p *godoc.Presentation, html bool) {
	p.PackageText = readTemplate("package.txt")
	p.SearchText = readTemplate("search.txt")

	if html {
		codewalkHTML = readTemplate("codewalk.html")
		codewalkdirHTML = readTemplate("codewalkdir.html")
		p.DirlistHTML = readTemplate("dirlist.html")
		p.ErrorHTML = readTemplate("error.html")
		p.ExampleHTML = readTemplate("example.html")
		p.GodocHTML = readTemplate("godoc.html")
		p.PackageHTML = readTemplate("package.html")
		p.SearchHTML = readTemplate("search.html")
		p.SearchDescXML = readTemplate("opensearch.xml")
	}
}

// Packages that were renamed between r60 and go1.
var pkgRedirects = map[string]string{
	"asn1":              "encoding/asn1",
	"big":               "math/big",
	"cmath":             "math/cmplx",
	"csv":               "encoding/csv",
	"exec":              "os/exec",
	"exp/template/html": "html/template",
	"gob":               "encoding/gob",
	"http":              "net/http",
	"http/cgi":          "net/http/cgi",
	"http/fcgi":         "net/http/fcgi",
	"http/httptest":     "net/http/httptest",
	"http/pprof":        "net/http/pprof",
	"json":              "encoding/json",
	"mail":              "net/mail",
	"rand":              "math/rand",
	"rpc":               "net/rpc",
	"rpc/jsonrpc":       "net/rpc/jsonrpc",
	"scanner":           "text/scanner",
	"smtp":              "net/smtp",
	"tabwriter":         "text/tabwriter",
	"template":          "text/template",
	"template/parse":    "text/template/parse",
	"url":               "net/url",
	"utf16":             "unicode/utf16",
	"utf8":              "unicode/utf8",
	"xml":               "encoding/xml",
}

// Commands that were renamed between r60 and go1.
var cmdRedirects = map[string]string{
	"gofix":     "fix",
	"goinstall": "go",
	"gopack":    "pack",
	"gotest":    "go",
	"govet":     "vet",
	"goyacc":    "yacc",
}

var redirects = map[string]string{
	"/blog":       "http://blog.golang.org",
	"/build":      "http://build.golang.org",
	"/change":     "https://code.google.com/p/go/source/list",
	"/cl":         "https://gocodereview.appspot.com/",
	"/cmd/godoc/": "http://godoc.org/code.google.com/p/go.tools/cmd/godoc/",
	"/cmd/vet/":   "http://godoc.org/code.google.com/p/go.tools/cmd/vet/",
	"/issue":      "https://code.google.com/p/go/issues",
	"/issue/new":  "https://code.google.com/p/go/issues/entry",
	"/issues":     "https://code.google.com/p/go/issues",
	"/play":       "http://play.golang.org",
	"/ref":        "/doc/#references",
	"/ref/":       "/doc/#references",
	"/ref/mem":    "/doc/mem",
	"/ref/spec":   "/doc/spec",
	"/talks":      "http://talks.golang.org",
	"/tour":       "http://tour.golang.org",
	"/wiki":       "https://code.google.com/p/go-wiki/w/list",

	"/doc/articles/c_go_cgo.html":                    "/blog/c-go-cgo",
	"/doc/articles/concurrency_patterns.html":        "/blog/go-concurrency-patterns-timing-out-and",
	"/doc/articles/defer_panic_recover.html":         "/blog/defer-panic-and-recover",
	"/doc/articles/error_handling.html":              "/blog/error-handling-and-go",
	"/doc/articles/gobs_of_data.html":                "/blog/gobs-of-data",
	"/doc/articles/godoc_documenting_go_code.html":   "/blog/godoc-documenting-go-code",
	"/doc/articles/gos_declaration_syntax.html":      "/blog/gos-declaration-syntax",
	"/doc/articles/image_draw.html":                  "/blog/go-imagedraw-package",
	"/doc/articles/image_package.html":               "/blog/go-image-package",
	"/doc/articles/json_and_go.html":                 "/blog/json-and-go",
	"/doc/articles/json_rpc_tale_of_interfaces.html": "/blog/json-rpc-tale-of-interfaces",
	"/doc/articles/laws_of_reflection.html":          "/blog/laws-of-reflection",
	"/doc/articles/race_detector.html":               "/blog/race-detector",
	"/doc/articles/slices_usage_and_internals.html":  "/blog/go-slices-usage-and-internals",
	"/doc/go_for_cpp_programmers.html":               "https://code.google.com/p/go-wiki/wiki/GoForCPPProgrammers",
	"/doc/go_tutorial.html":                          "http://tour.golang.org/",
}

var prefixHelpers = map[string]string{
	"blog":   "http://blog.golang.org/",
	"change": "https://code.google.com/p/go/source/detail?r=",
	"cl":     "https://codereview.appspot.com/",
	"issue":  "https://code.google.com/p/go/issues/detail?id=",
	"play":   "http://play.golang.org/",
	"talks":  "http://talks.golang.org/",
	"wiki":   "https://code.google.com/p/go-wiki/wiki/",
}

func handlePathRedirects(redirects map[string]string, prefix string) {
	for source, target := range pkgRedirects {
		h := makeRedirectHandler(prefix + target + "/")
		p := prefix + source
		http.HandleFunc(p, h)
		http.HandleFunc(p+"/", h)
	}
}

func makeRedirectHandler(target string) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, target, http.StatusMovedPermanently)
	}
}

var validId = regexp.MustCompile(`^[A-Za-z0-9-]*$`)

func makePrefixRedirectHandler(prefix, baseURL string) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if p := r.URL.Path; p == prefix {
			// redirect /prefix/ to /prefix
			http.Redirect(w, r, p[:len(p)-1], http.StatusFound)
			return
		}
		id := r.URL.Path[len(prefix):]
		if !validId.MatchString(id) {
			http.Error(w, "Not found", http.StatusNotFound)
			return
		}
		target := baseURL + id
		http.Redirect(w, r, target, http.StatusFound)
	}
}
<|endoftext|>


<commit_before>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	stdtesting "testing"

	"launchpad.net/gnuflag"
	gc "launchpad.net/gocheck"

	"launchpad.net/juju-core/cmd"
	"launchpad.net/juju-core/juju/osenv"
	_ "launchpad.net/juju-core/provider/dummy"
	"launchpad.net/juju-core/testing"
	"launchpad.net/juju-core/version"
)

func TestPackage(t *stdtesting.T) {
	testing.MgoTestPackage(t)
}

type MainSuite struct {
	testing.FakeHomeSuite
}

var _ = gc.Suite(&MainSuite{})

var (
	flagRunMain = flag.Bool("run-main", false, "Run the application's main function for recursive testing")
)

// Reentrancy point for testing (something as close as possible to) the juju
// tool itself.
func TestRunMain(t *stdtesting.T) {
	if *flagRunMain {
		Main(flag.Args())
	}
}

func badrun(c *gc.C, exit int, args ...string) string {
	localArgs := append([]string{"-test.run", "TestRunMain", "-run-main", "--", "juju"}, args...)
	ps := exec.Command(os.Args[0], localArgs...)
	ps.Env = append(os.Environ(), osenv.JujuHomeEnvKey+"="+osenv.JujuHome())
	output, err := ps.CombinedOutput()
	c.Logf("command output: %q", output)
	if exit != 0 {
		c.Assert(err, gc.ErrorMatches, fmt.Sprintf("exit status %d", exit))
	}
	return string(output)
}

func helpText(command cmd.Command, name string) string {
	buff := &bytes.Buffer{}
	info := command.Info()
	info.Name = name
	f := gnuflag.NewFlagSet(info.Name, gnuflag.ContinueOnError)
	command.SetFlags(f)
	buff.Write(info.Help(f))
	return buff.String()
}

func deployHelpText() string {
	return helpText(&DeployCommand{}, "juju deploy")
}

func syncToolsHelpText() string {
	return helpText(&SyncToolsCommand{}, "juju sync-tools")
}

func (s *MainSuite) TestRunMain(c *gc.C) {
	defer testing.MakeSampleHome(c).Restore()
	// The test array structure needs to be inline here as some of the
	// expected values below use deployHelpText().  This constructs the deploy
	// command and runs gets the help for it.  When the deploy command is
	// setting the flags (which is needed for the help text) it is accessing
	// osenv.JujuHome(), which panics if SetJujuHome has not been called.
	// The FakeHome from testing does this.
	for i, t := range []struct {
		summary string
		args    []string
		code    int
		out     string
	}{{
		summary: "no params shows help",
		args:    []string{},
		code:    0,
		out:     strings.TrimLeft(helpBasics, "\n"),
	}, {
		summary: "juju help is the same as juju",
		args:    []string{"help"},
		code:    0,
		out:     strings.TrimLeft(helpBasics, "\n"),
	}, {
		summary: "juju --help works too",
		args:    []string{"--help"},
		code:    0,
		out:     strings.TrimLeft(helpBasics, "\n"),
	}, {
		summary: "juju help basics is the same as juju",
		args:    []string{"help", "basics"},
		code:    0,
		out:     strings.TrimLeft(helpBasics, "\n"),
	}, {
		summary: "juju help foo doesn't exist",
		args:    []string{"help", "foo"},
		code:    1,
		out:     "ERROR unknown command or topic for foo\n",
	}, {
		summary: "juju help deploy shows the default help without global options",
		args:    []string{"help", "deploy"},
		code:    0,
		out:     deployHelpText(),
	}, {
		summary: "juju --help deploy shows the same help as 'help deploy'",
		args:    []string{"--help", "deploy"},
		code:    0,
		out:     deployHelpText(),
	}, {
		summary: "juju deploy --help shows the same help as 'help deploy'",
		args:    []string{"deploy", "--help"},
		code:    0,
		out:     deployHelpText(),
	}, {
		summary: "unknown command",
		args:    []string{"discombobulate"},
		code:    1,
		out:     "ERROR unrecognized command: juju discombobulate\n",
	}, {
		summary: "unknown option before command",
		args:    []string{"--cheese", "bootstrap"},
		code:    2,
		out:     "error: flag provided but not defined: --cheese\n",
	}, {
		summary: "unknown option after command",
		args:    []string{"bootstrap", "--cheese"},
		code:    2,
		out:     "error: flag provided but not defined: --cheese\n",
	}, {
		summary: "known option, but specified before command",
		args:    []string{"--environment", "blah", "bootstrap"},
		code:    2,
		out:     "error: flag provided but not defined: --environment\n",
	}, {
		summary: "juju sync-tools registered properly",
		args:    []string{"sync-tools", "--help"},
		code:    0,
		out:     syncToolsHelpText(),
	}, {
		summary: "check version command registered properly",
		args:    []string{"version"},
		code:    0,
		out:     version.Current.String() + "\n",
	},
	} {
		c.Logf("test %d: %s", i, t.summary)
		out := badrun(c, t.code, t.args...)
		c.Assert(out, gc.Equals, t.out)
	}
}

var brokenConfig = `
'
`

// breakJuju writes a dummy environment with incomplete configuration.
// environMethod is called.
func breakJuju(c *gc.C, environMethod string) (msg string) {
	path := osenv.JujuHomePath("environments.yaml")
	err := ioutil.WriteFile(path, []byte(brokenConfig), 0666)
	c.Assert(err, gc.IsNil)
	return `cannot parse "[^"]*": YAML error.*`
}

func (s *MainSuite) TestActualRunJujuArgsBeforeCommand(c *gc.C) {
	c.Skip("breaks test isolation: lp:1233601")
	defer testing.MakeFakeHomeNoEnvironments(c, "one").Restore()
	// Check global args work when specified before command
	msg := breakJuju(c, "Bootstrap")
	logpath := filepath.Join(c.MkDir(), "log")
	out := badrun(c, 1, "--log-file", logpath, "bootstrap")
	fullmsg := fmt.Sprintf(`(.|\n)*ERROR .*%s\n`, msg)
	c.Assert(out, gc.Matches, fullmsg)
	content, err := ioutil.ReadFile(logpath)
	c.Assert(err, gc.IsNil)
	c.Assert(string(content), gc.Matches, fullmsg)
}

func (s *MainSuite) TestActualRunJujuArgsAfterCommand(c *gc.C) {
	c.Skip("breaks test isolation: lp:1233601")
	defer testing.MakeFakeHomeNoEnvironments(c, "one").Restore()
	// Check global args work when specified after command
	msg := breakJuju(c, "Bootstrap")
	logpath := filepath.Join(c.MkDir(), "log")
	out := badrun(c, 1, "bootstrap", "--log-file", logpath)
	fullmsg := fmt.Sprintf(`(.|\n)*ERROR .*%s\n`, msg)
	c.Assert(out, gc.Matches, fullmsg)
	content, err := ioutil.ReadFile(logpath)
	c.Assert(err, gc.IsNil)
	c.Assert(string(content), gc.Matches, fullmsg)
}

var commandNames = []string{
	"add-machine",
	"add-relation",
	"add-unit",
	"api-endpoints",
	"authorised-keys",
	"bootstrap",
	"debug-hooks",
	"debug-log",
	"deploy",
	"destroy-environment",
	"destroy-machine",
	"destroy-relation",
	"destroy-service",
	"destroy-unit",
	"env", // alias for switch
	"expose",
	"generate-config", // alias for init
	"get",
	"get-constraints",
	"get-env", // alias for get-environment
	"get-environment",
	"help",
	"help-tool",
	"init",
	"publish",
	"remove-machine",  // alias for destroy-machine
	"remove-relation", // alias for destroy-relation
	"remove-service",  // alias for destroy-service
	"remove-unit",     // alias for destroy-unit
	"resolved",
	"run",
	"scp",
	"set",
	"set-constraints",
	"set-env", // alias for set-environment
	"set-environment",
	"ssh",
	"stat", // alias for status
	"status",
	"switch",
	"sync-tools",
	"terminate-machine", // alias for destroy-machine
	"unexpose",
	"unset",
	"upgrade-charm",
	"upgrade-juju",
	"version",
}

func (s *MainSuite) TestHelpCommands(c *gc.C) {
	// Check that we have correctly registered all the commands
	// by checking the help output.
	defer osenv.SetJujuHome(osenv.SetJujuHome(c.MkDir()))
	out := badrun(c, 0, "help", "commands")
	lines := strings.Split(out, "\n")
	var names []string
	for _, line := range lines {
		f := strings.Fields(line)
		if len(f) == 0 {
			continue
		}
		names = append(names, f[0])
	}
	// The names should be output in alphabetical order, so don't sort.
	c.Assert(names, gc.DeepEquals, commandNames)
}

var topicNames = []string{
	"azure-provider",
	"basics",
	"commands",
	"constraints",
	"ec2-provider",
	"global-options",
	"glossary",
	"hpcloud-provider",
	"local-provider",
	"logging",
	"openstack-provider",
	"plugins",
	"topics",
}

func (s *MainSuite) TestHelpTopics(c *gc.C) {
	// Check that we have correctly registered all the topics
	// by checking the help output.
	defer osenv.SetJujuHome(osenv.SetJujuHome(c.MkDir()))
	out := badrun(c, 0, "help", "topics")
	lines := strings.Split(out, "\n")
	var names []string
	for _, line := range lines {
		f := strings.Fields(line)
		if len(f) == 0 {
			continue
		}
		names = append(names, f[0])
	}
	// The names should be output in alphabetical order, so don't sort.
	c.Assert(names, gc.DeepEquals, topicNames)
}

var globalFlags = []string{
	"--debug .*",
	"--description .*",
	"-h, --help .*",
	"--log-file .*",
	"--logging-config .*",
	"--show-log .*",
	"-v, --verbose .*",
}

func (s *MainSuite) TestHelpGlobalOptions(c *gc.C) {
	// Check that we have correctly registered all the topics
	// by checking the help output.
	defer osenv.SetJujuHome(osenv.SetJujuHome(c.MkDir()))
	out := badrun(c, 0, "help", "global-options")
	c.Assert(out, gc.Matches, `Global Options

These options may be used with any command, and may appear in front of any
command\.(.|\n)*`)
	lines := strings.Split(out, "\n")
	var flags []string
	for _, line := range lines {
		f := strings.Fields(line)
		if len(f) == 0 || line[0] != '-' {
			continue
		}
		flags = append(flags, line)
	}
	c.Assert(len(flags), gc.Equals, len(globalFlags))
	for i, line := range flags {
		c.Assert(line, gc.Matches, globalFlags[i])
	}
}
<commit_msg>Add quiet flag to the test.<commit_after>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	stdtesting "testing"

	"launchpad.net/gnuflag"
	gc "launchpad.net/gocheck"

	"launchpad.net/juju-core/cmd"
	"launchpad.net/juju-core/juju/osenv"
	_ "launchpad.net/juju-core/provider/dummy"
	"launchpad.net/juju-core/testing"
	"launchpad.net/juju-core/version"
)

func TestPackage(t *stdtesting.T) {
	testing.MgoTestPackage(t)
}

type MainSuite struct {
	testing.FakeHomeSuite
}

var _ = gc.Suite(&MainSuite{})

var (
	flagRunMain = flag.Bool("run-main", false, "Run the application's main function for recursive testing")
)

// Reentrancy point for testing (something as close as possible to) the juju
// tool itself.
func TestRunMain(t *stdtesting.T) {
	if *flagRunMain {
		Main(flag.Args())
	}
}

func badrun(c *gc.C, exit int, args ...string) string {
	localArgs := append([]string{"-test.run", "TestRunMain", "-run-main", "--", "juju"}, args...)
	ps := exec.Command(os.Args[0], localArgs...)
	ps.Env = append(os.Environ(), osenv.JujuHomeEnvKey+"="+osenv.JujuHome())
	output, err := ps.CombinedOutput()
	c.Logf("command output: %q", output)
	if exit != 0 {
		c.Assert(err, gc.ErrorMatches, fmt.Sprintf("exit status %d", exit))
	}
	return string(output)
}

func helpText(command cmd.Command, name string) string {
	buff := &bytes.Buffer{}
	info := command.Info()
	info.Name = name
	f := gnuflag.NewFlagSet(info.Name, gnuflag.ContinueOnError)
	command.SetFlags(f)
	buff.Write(info.Help(f))
	return buff.String()
}

func deployHelpText() string {
	return helpText(&DeployCommand{}, "juju deploy")
}

func syncToolsHelpText() string {
	return helpText(&SyncToolsCommand{}, "juju sync-tools")
}

func (s *MainSuite) TestRunMain(c *gc.C) {
	defer testing.MakeSampleHome(c).Restore()
	// The test array structure needs to be inline here as some of the
	// expected values below use deployHelpText().  This constructs the deploy
	// command and runs gets the help for it.  When the deploy command is
	// setting the flags (which is needed for the help text) it is accessing
	// osenv.JujuHome(), which panics if SetJujuHome has not been called.
	// The FakeHome from testing does this.
	for i, t := range []struct {
		summary string
		args    []string
		code    int
		out     string
	}{{
		summary: "no params shows help",
		args:    []string{},
		code:    0,
		out:     strings.TrimLeft(helpBasics, "\n"),
	}, {
		summary: "juju help is the same as juju",
		args:    []string{"help"},
		code:    0,
		out:     strings.TrimLeft(helpBasics, "\n"),
	}, {
		summary: "juju --help works too",
		args:    []string{"--help"},
		code:    0,
		out:     strings.TrimLeft(helpBasics, "\n"),
	}, {
		summary: "juju help basics is the same as juju",
		args:    []string{"help", "basics"},
		code:    0,
		out:     strings.TrimLeft(helpBasics, "\n"),
	}, {
		summary: "juju help foo doesn't exist",
		args:    []string{"help", "foo"},
		code:    1,
		out:     "ERROR unknown command or topic for foo\n",
	}, {
		summary: "juju help deploy shows the default help without global options",
		args:    []string{"help", "deploy"},
		code:    0,
		out:     deployHelpText(),
	}, {
		summary: "juju --help deploy shows the same help as 'help deploy'",
		args:    []string{"--help", "deploy"},
		code:    0,
		out:     deployHelpText(),
	}, {
		summary: "juju deploy --help shows the same help as 'help deploy'",
		args:    []string{"deploy", "--help"},
		code:    0,
		out:     deployHelpText(),
	}, {
		summary: "unknown command",
		args:    []string{"discombobulate"},
		code:    1,
		out:     "ERROR unrecognized command: juju discombobulate\n",
	}, {
		summary: "unknown option before command",
		args:    []string{"--cheese", "bootstrap"},
		code:    2,
		out:     "error: flag provided but not defined: --cheese\n",
	}, {
		summary: "unknown option after command",
		args:    []string{"bootstrap", "--cheese"},
		code:    2,
		out:     "error: flag provided but not defined: --cheese\n",
	}, {
		summary: "known option, but specified before command",
		args:    []string{"--environment", "blah", "bootstrap"},
		code:    2,
		out:     "error: flag provided but not defined: --environment\n",
	}, {
		summary: "juju sync-tools registered properly",
		args:    []string{"sync-tools", "--help"},
		code:    0,
		out:     syncToolsHelpText(),
	}, {
		summary: "check version command registered properly",
		args:    []string{"version"},
		code:    0,
		out:     version.Current.String() + "\n",
	},
	} {
		c.Logf("test %d: %s", i, t.summary)
		out := badrun(c, t.code, t.args...)
		c.Assert(out, gc.Equals, t.out)
	}
}

var brokenConfig = `
'
`

// breakJuju writes a dummy environment with incomplete configuration.
// environMethod is called.
func breakJuju(c *gc.C, environMethod string) (msg string) {
	path := osenv.JujuHomePath("environments.yaml")
	err := ioutil.WriteFile(path, []byte(brokenConfig), 0666)
	c.Assert(err, gc.IsNil)
	return `cannot parse "[^"]*": YAML error.*`
}

func (s *MainSuite) TestActualRunJujuArgsBeforeCommand(c *gc.C) {
	c.Skip("breaks test isolation: lp:1233601")
	defer testing.MakeFakeHomeNoEnvironments(c, "one").Restore()
	// Check global args work when specified before command
	msg := breakJuju(c, "Bootstrap")
	logpath := filepath.Join(c.MkDir(), "log")
	out := badrun(c, 1, "--log-file", logpath, "bootstrap")
	fullmsg := fmt.Sprintf(`(.|\n)*ERROR .*%s\n`, msg)
	c.Assert(out, gc.Matches, fullmsg)
	content, err := ioutil.ReadFile(logpath)
	c.Assert(err, gc.IsNil)
	c.Assert(string(content), gc.Matches, fullmsg)
}

func (s *MainSuite) TestActualRunJujuArgsAfterCommand(c *gc.C) {
	c.Skip("breaks test isolation: lp:1233601")
	defer testing.MakeFakeHomeNoEnvironments(c, "one").Restore()
	// Check global args work when specified after command
	msg := breakJuju(c, "Bootstrap")
	logpath := filepath.Join(c.MkDir(), "log")
	out := badrun(c, 1, "bootstrap", "--log-file", logpath)
	fullmsg := fmt.Sprintf(`(.|\n)*ERROR .*%s\n`, msg)
	c.Assert(out, gc.Matches, fullmsg)
	content, err := ioutil.ReadFile(logpath)
	c.Assert(err, gc.IsNil)
	c.Assert(string(content), gc.Matches, fullmsg)
}

var commandNames = []string{
	"add-machine",
	"add-relation",
	"add-unit",
	"api-endpoints",
	"authorised-keys",
	"bootstrap",
	"debug-hooks",
	"debug-log",
	"deploy",
	"destroy-environment",
	"destroy-machine",
	"destroy-relation",
	"destroy-service",
	"destroy-unit",
	"env", // alias for switch
	"expose",
	"generate-config", // alias for init
	"get",
	"get-constraints",
	"get-env", // alias for get-environment
	"get-environment",
	"help",
	"help-tool",
	"init",
	"publish",
	"remove-machine",  // alias for destroy-machine
	"remove-relation", // alias for destroy-relation
	"remove-service",  // alias for destroy-service
	"remove-unit",     // alias for destroy-unit
	"resolved",
	"run",
	"scp",
	"set",
	"set-constraints",
	"set-env", // alias for set-environment
	"set-environment",
	"ssh",
	"stat", // alias for status
	"status",
	"switch",
	"sync-tools",
	"terminate-machine", // alias for destroy-machine
	"unexpose",
	"unset",
	"upgrade-charm",
	"upgrade-juju",
	"version",
}

func (s *MainSuite) TestHelpCommands(c *gc.C) {
	// Check that we have correctly registered all the commands
	// by checking the help output.
	defer osenv.SetJujuHome(osenv.SetJujuHome(c.MkDir()))
	out := badrun(c, 0, "help", "commands")
	lines := strings.Split(out, "\n")
	var names []string
	for _, line := range lines {
		f := strings.Fields(line)
		if len(f) == 0 {
			continue
		}
		names = append(names, f[0])
	}
	// The names should be output in alphabetical order, so don't sort.
	c.Assert(names, gc.DeepEquals, commandNames)
}

var topicNames = []string{
	"azure-provider",
	"basics",
	"commands",
	"constraints",
	"ec2-provider",
	"global-options",
	"glossary",
	"hpcloud-provider",
	"local-provider",
	"logging",
	"openstack-provider",
	"plugins",
	"topics",
}

func (s *MainSuite) TestHelpTopics(c *gc.C) {
	// Check that we have correctly registered all the topics
	// by checking the help output.
	defer osenv.SetJujuHome(osenv.SetJujuHome(c.MkDir()))
	out := badrun(c, 0, "help", "topics")
	lines := strings.Split(out, "\n")
	var names []string
	for _, line := range lines {
		f := strings.Fields(line)
		if len(f) == 0 {
			continue
		}
		names = append(names, f[0])
	}
	// The names should be output in alphabetical order, so don't sort.
	c.Assert(names, gc.DeepEquals, topicNames)
}

var globalFlags = []string{
	"--debug .*",
	"--description .*",
	"-h, --help .*",
	"--log-file .*",
	"--logging-config .*",
	"-q, --quiet .*",
	"--show-log .*",
	"-v, --verbose .*",
}

func (s *MainSuite) TestHelpGlobalOptions(c *gc.C) {
	// Check that we have correctly registered all the topics
	// by checking the help output.
	defer osenv.SetJujuHome(osenv.SetJujuHome(c.MkDir()))
	out := badrun(c, 0, "help", "global-options")
	c.Assert(out, gc.Matches, `Global Options

These options may be used with any command, and may appear in front of any
command\.(.|\n)*`)
	lines := strings.Split(out, "\n")
	var flags []string
	for _, line := range lines {
		f := strings.Fields(line)
		if len(f) == 0 || line[0] != '-' {
			continue
		}
		flags = append(flags, line)
	}
	c.Assert(len(flags), gc.Equals, len(globalFlags))
	for i, line := range flags {
		c.Assert(line, gc.Matches, globalFlags[i])
	}
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"net"
	"time"

	"github.com/pkg/errors"

	"google.golang.org/grpc"
	grpcstatus "google.golang.org/grpc/status"

	"github.com/havoc-io/mutagen/pkg/daemon"
	mgrpc "github.com/havoc-io/mutagen/pkg/grpc"
)

func daemonDialer(_ string, timeout time.Duration) (net.Conn, error) {
	return daemon.DialTimeout(timeout)
}

func createDaemonClientConnection() (*grpc.ClientConn, error) {
	// Create a context to timeout the dial.
	dialContext, cancel := context.WithTimeout(
		context.Background(),
		daemon.RecommendedDialTimeout,
	)
	defer cancel()

	// Perform dialing.
	return grpc.DialContext(
		dialContext,
		"",
		grpc.WithInsecure(),
		grpc.WithDialer(daemonDialer),
		grpc.WithBlock(),
		grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(mgrpc.MaximumIPCMessageSize)),
		grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(mgrpc.MaximumIPCMessageSize)),
	)
}

func peelAwayRPCErrorLayer(err error) error {
	if status, ok := grpcstatus.FromError(err); !ok {
		return err
	} else {
		return errors.New(status.Message())
	}
}
<commit_msg>Added more helpful error message for daemon connection timeout.<commit_after>package main

import (
	"context"
	"net"
	"time"

	"github.com/pkg/errors"

	"google.golang.org/grpc"
	grpcstatus "google.golang.org/grpc/status"

	"github.com/havoc-io/mutagen/pkg/daemon"
	mgrpc "github.com/havoc-io/mutagen/pkg/grpc"
)

func daemonDialer(_ string, timeout time.Duration) (net.Conn, error) {
	return daemon.DialTimeout(timeout)
}

func createDaemonClientConnection() (*grpc.ClientConn, error) {
	// Create a context to timeout the dial.
	dialContext, cancel := context.WithTimeout(
		context.Background(),
		daemon.RecommendedDialTimeout,
	)
	defer cancel()

	// Perform dialing.
	connection, err := grpc.DialContext(
		dialContext,
		"",
		grpc.WithInsecure(),
		grpc.WithDialer(daemonDialer),
		grpc.WithBlock(),
		grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(mgrpc.MaximumIPCMessageSize)),
		grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(mgrpc.MaximumIPCMessageSize)),
	)
	if err != nil {
		if err == context.DeadlineExceeded {
			return nil, errors.New("connection timed out (is the daemon running?)")
		}
		return nil, err
	}

	// Success.
	return connection, nil
}

func peelAwayRPCErrorLayer(err error) error {
	if status, ok := grpcstatus.FromError(err); !ok {
		return err
	} else {
		return errors.New(status.Message())
	}
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"

	"github.com/mobingi/mobingi-cli/pkg/cli"
	"github.com/mobingi/mobingi-cli/pkg/registry"
	"github.com/mobingilabs/mobingi-sdk-go/pkg/cmdline"
	d "github.com/mobingilabs/mobingi-sdk-go/pkg/debug"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

func RegistryToken() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "token",
		Short: "get registry token",
		Long: `Get registry token. This command supports '--fmt=raw' option. By default,
it will only print the token value.

Example:

  $ ` + cmdline.Args0() + ` registry token \
      --username=foo \
      --password=bar \
      --scope="repository:foo/sample:pull"`,
		Run: token,
	}

	cmd.Flags().SortFlags = false
	cmd.Flags().String("username", "", "username (account subuser)")
	cmd.Flags().String("password", "", "password (account subuser)")
	cmd.Flags().String("service", "Mobingi Docker Registry", "service for authentication")
	cmd.Flags().String("scope", "", "scope for authentication")
	return cmd
}

func token(cmd *cobra.Command, args []string) {
	userpass := userPass(cmd)
	base := viper.GetString("api_url")
	apiver := cli.GetCliStringFlag(cmd, "apiver")
	svc := cli.GetCliStringFlag(cmd, "service")
	scope := cli.GetCliStringFlag(cmd, "scope")

	body, token, err := registry.GetRegistryToken(
		&registry.TokenParams{
			Base:       base,
			ApiVersion: apiver,
			TokenCreds: &registry.TokenCredentials{
				UserPass: userpass,
				Service:  svc,
				Scope:    scope,
			},
		},
	)

	cli.ErrorExit(err, 1)

	pfmt := cli.GetCliStringFlag(cmd, "fmt")
	switch pfmt {
	case "raw":
		fmt.Println(string(body))
	default:
		d.Info("token:", token)
	}
}
<commit_msg>Use sdk in registry token.<commit_after>package cmd

import (
	"fmt"

	"github.com/mobingi/mobingi-cli/pkg/cli"
	"github.com/mobingilabs/mobingi-sdk-go/mobingi/registry"
	"github.com/mobingilabs/mobingi-sdk-go/pkg/cmdline"
	d "github.com/mobingilabs/mobingi-sdk-go/pkg/debug"
	"github.com/spf13/cobra"
)

func RegistryToken() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "token",
		Short: "get registry token",
		Long: `Get registry token. This command supports '--fmt=raw' option. By default,
it will only print the token value.

Example:

  $ ` + cmdline.Args0() + ` registry token \
      --username=foo \
      --password=bar \
      --scope="repository:foo/sample:pull"`,
		Run: token,
	}

	cmd.Flags().SortFlags = false
	cmd.Flags().String("username", "", "username (account subuser)")
	cmd.Flags().String("password", "", "password (account subuser)")
	cmd.Flags().String("service", "Mobingi Docker Registry", "service for authentication")
	cmd.Flags().String("scope", "", "scope for authentication")
	return cmd
}

func token(cmd *cobra.Command, args []string) {
	service := cli.GetCliStringFlag(cmd, "service")
	scope := cli.GetCliStringFlag(cmd, "scope")
	sess, err := clisession()
	cli.ErrorExit(err, 1)

	ensureUserPass(cmd, sess)
	svc := registry.New(sess)
	in := &registry.GetRegistryTokenInput{
		Service: service,
		Scope:   scope,
	}

	resp, body, token, err := svc.GetRegistryToken(in)
	cli.ErrorExit(err, 1)
	exitOn401(resp)

	pfmt := cli.GetCliStringFlag(cmd, "fmt")
	switch pfmt {
	case "raw":
		fmt.Println(string(body))
	default:
		d.Info("token:", token)
	}
}
<|endoftext|>


<commit_before>package cmd

import (
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"time"

	"github.com/spf13/cobra"
)

var downloadURL = "https://github.com/karimra/gnmic/raw/master/install.sh"

// upgradeCmd represents the version command
var upgradeCmd = &cobra.Command{
	Use:   "upgrade",
	Short: "upgrade gnmic to latest available version",

	RunE: func(cmd *cobra.Command, args []string) error {
		f, err := ioutil.TempFile("", "gnmic")
		defer os.Remove(f.Name())
		if err != nil {
			return err
		}
		err = downloadFile(downloadURL, f)
		if err != nil {
			return err
		}

		c := exec.Command("bash", f.Name())
		c.Stdout = os.Stdout
		c.Stderr = os.Stderr
		err = c.Run()
		if err != nil {
			return err
		}
		return nil
	},
}

// downloadFile will download a file from a URL and write its content to a file
func downloadFile(url string, file *os.File) error {
	client := http.Client{Timeout: 10 * time.Second}
	// Get the data
	resp, err := client.Get(url)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	// Write the body to file
	_, err = io.Copy(file, resp.Body)
	if err != nil {
		return err
	}
	return nil
}

func init() {
	versionCmd.AddCommand(upgradeCmd)
}
<commit_msg>added package upgrade option<commit_after>package cmd

import (
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"time"

	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var downloadURL = "https://github.com/karimra/gnmic/raw/master/install.sh"

// upgradeCmd represents the version command
var upgradeCmd = &cobra.Command{
	Use:   "upgrade",
	Short: "upgrade gnmic to latest available version",

	RunE: func(cmd *cobra.Command, args []string) error {
		f, err := ioutil.TempFile("", "gnmic")
		defer os.Remove(f.Name())
		if err != nil {
			return err
		}
		err = downloadFile(downloadURL, f)
		if err != nil {
			return err
		}

		var c *exec.Cmd
		switch viper.GetBool("upgrade-use-pkg") {
		case true:
			c = exec.Command("bash", f.Name(), "--use-pkg")
		case false:
			c = exec.Command("bash", f.Name())
		}

		c.Stdout = os.Stdout
		c.Stderr = os.Stderr
		err = c.Run()
		if err != nil {
			return err
		}
		return nil
	},
}

// downloadFile will download a file from a URL and write its content to a file
func downloadFile(url string, file *os.File) error {
	client := http.Client{Timeout: 10 * time.Second}
	// Get the data
	resp, err := client.Get(url)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	// Write the body to file
	_, err = io.Copy(file, resp.Body)
	if err != nil {
		return err
	}
	return nil
}

func init() {
	versionCmd.AddCommand(upgradeCmd)
	upgradeCmd.Flags().Bool("use-pkg", false, "upgrade using package")
	viper.BindPFlag("upgrade-use-pkg", upgradeCmd.LocalFlags().Lookup("use-pkg"))
}
<|endoftext|>


<commit_before>package status

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/fatih/color"
	"github.com/taskcluster/taskcluster-cli/cmds/root"

	"github.com/shibukawa/configdir"
	"github.com/spf13/cobra"
)

const (
	manifestURL = "https://references.taskcluster.net/manifest.json"
)

var (
	pingURLs          PingURLs
	validArgs         []string
	cache             = Cache()
	pingURLsCachePath = filepath.Join("cmds", "status", "pingURLs.json")
)

type (
	PingURLs map[string]string

	CachedURLs struct {
		LastUpdated time.Time `json:"lastUpdated"`
		PingURLs    PingURLs  `json:"pingURLs"`
	}

	PingResponse struct {
		Alive  bool    `json:"alive"`
		Uptime float64 `json:"uptime"`
	}

	API struct {
		BaseURL string     `json:"baseUrl"`
		Entries []APIEntry `json:"entries"`
	}

	APIEntry struct {
		Name  string `json:"name"`
		Route string `json:"route"`
	}
)

// CacheFilePath returns the file system path to the cache file storing the ping URLs
func Cache() (cache *configdir.Config) {
	configDirs := configdir.New("taskcluster", "taskcluster-cli")
	cache = configDirs.QueryCacheFolder()
	return
}

func init() {
	var err error
	pingURLs, err = NewPingURLs()
	if err != nil {
		panic(err)
	}

	validArgs = make([]string, len(pingURLs))
	i := 0
	for k := range pingURLs {
		validArgs[i] = k
		i++
	}
	use := "status"
	for _, validArg := range validArgs {
		use = use + " [" + validArg + "]"
	}
	statusCmd := &cobra.Command{
		Short: "taskcluster-cli status will query the current running status of taskcluster services",
		Long: `When called without arguments, taskcluster-cli status will return the current running
status of all production taskcluster services.

By specifying one or more optional services as arguments, you can limit the
services included in the status report.`,
		PreRunE:            preRun,
		Use:                use,
		ValidArgs:          validArgs,
		RunE:               status,
		DisableFlagParsing: true,
	}

	// Add the task subtree to the root.
	root.Command.AddCommand(statusCmd)
}

// NewPingURLs returns the ping URLs to use. The caller does not need to be
// concerned about whether these URLs are retrieved from a local cache, or from
// querying web services.
func NewPingURLs() (pingURLs PingURLs, err error) {
	if !cache.Exists(pingURLsCachePath) {
		return RefreshCache(manifestURL, cache, pingURLsCachePath)
	}
	cachedURLs, err := ReadCachedURLsFile(cache, pingURLsCachePath)
	if err != nil {
		return
	}
	if cachedURLs.Expired(time.Hour * 24) {
		return RefreshCache(manifestURL, cache, pingURLsCachePath)
	}
	pingURLs = cachedURLs.PingURLs
	return
}

// RefreshCache will scrape the manifest url for a dictionary of taskcluster
// services, and cache the results in file at path.
func RefreshCache(manifestURL string, cache *configdir.Config, cachePath string) (pingURLs PingURLs, err error) {
	pingURLs, err = ScrapePingURLs(manifestURL)
	if err != nil {
		return
	}
	cachedURLs, err := pingURLs.Cache(cache, cachePath)
	return cachedURLs.PingURLs, err
}

// ReadCachedURLsFile returns a *CachedURLs based on the contents of the file
// with the given path.
func ReadCachedURLsFile(cache *configdir.Config, cachePath string) (cachedURLs *CachedURLs, err error) {
	var cachedURLsBytes []byte
	cachedURLsBytes, err = cache.ReadFile(cachePath)
	if err != nil {
		return
	}
	err = json.Unmarshal(cachedURLsBytes, &cachedURLs)
	return
}

// Cache writes the pingURLs p to a file at path (replacing if it exists
// already, and creating parent folders, if required), using the current time
// for the retrieval timestamp.
func (p PingURLs) Cache(cache *configdir.Config, cachePath string) (cachedURLs *CachedURLs, err error) {
	color.Magenta("Writing cache file %v", filepath.Join(cache.Path, cachePath))

	///////////////////////////////////////////////////////////////////////
	// workaround until https://github.com/shibukawa/configdir/pull/2 lands
	parentDir := filepath.Dir(filepath.Join(cache.Path, cachePath))
	err = os.MkdirAll(parentDir, 0755)
	if err != nil {
		return
	}
	///////////////////////////////////////////////////////////////////////

	cachedURLs = &CachedURLs{
		LastUpdated: time.Now(),
		PingURLs:    p,
	}
	var bytes []byte
	bytes, err = json.MarshalIndent(cachedURLs, "", "  ")
	if err != nil {
		return
	}
	err = cache.WriteFile(cachePath, bytes)
	return
}

func (cachedURLs *CachedURLs) Expired(d time.Duration) bool {
	return time.Since(cachedURLs.LastUpdated) > d
}

func preRun(cmd *cobra.Command, args []string) error {
	return validateArgs(cmd, args)
}

//  ScrapePingURLs queries manifestURL to return a manifest of services, which
//  are then queried to fetch ping URLs for taskcluster services
func ScrapePingURLs(manifestURL string) (pingURLs PingURLs, err error) {
	color.Yellow("Scraping ping URLs from %v", manifestURL)
	var allAPIs map[string]string
	err = objectFromJsonURL(manifestURL, &allAPIs)
	if err != nil {
		return
	}
	pingURLs = map[string]string{}
	for _, apiURL := range allAPIs {
		reference := new(API)
		err = objectFromJsonURL(apiURL, reference)
		if err != nil {
			return
		}

		// loop through entries to find a /ping endpoint
		for _, entry := range reference.Entries {
			if entry.Name == "ping" {
				// determine hostname
				var u *url.URL
				u, err = url.Parse(reference.BaseURL)
				if err != nil {
					return
				}
				hostname := u.Hostname()
				service := strings.SplitN(hostname, ".", 2)[0]
				pingURLs[service] = reference.BaseURL + entry.Route
				break
			}
		}
	}
	return
}

func objectFromJsonURL(urlReturningJSON string, object interface{}) (err error) {
	resp, err := http.Get(urlReturningJSON)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if resp.StatusCode != 200 {
		return fmt.Errorf("Bad (!= 200) status code %v from (*URL) Hostnamerl %v", resp.StatusCode, urlReturningJSON)
	}
	decoder := json.NewDecoder(resp.Body)
	err = decoder.Decode(&object)
	if err != nil {
		return err
	}
	return nil
}

func validateArgs(cmd *cobra.Command, args []string) error {
outer:
	for _, arg := range args {
		for _, validArg := range cmd.ValidArgs {
			if arg == validArg {
				continue outer
			}
		}
		return fmt.Errorf("invalid argument(s) passed")
	}
	return nil
}

func respbody(service string) error {
	var servstat PingResponse
	err := objectFromJsonURL(pingURLs[service], &servstat)
	if err != nil {
		return err
	}
	if servstat.Alive == true {
		living := "Alive"
		fmt.Printf("      %v\n", service)
		color.Green("      %v\n", living)
	}

	return nil
}

func status(cmd *cobra.Command, args []string) error {
	if len(args) == 0 {
		args = validArgs
	}
	for _, service := range args {
		err := respbody(service)
		if err != nil {
			panic(err)
		}
	}
	return nil
}
<commit_msg>corrected doc comment<commit_after>package status

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/fatih/color"
	"github.com/taskcluster/taskcluster-cli/cmds/root"

	"github.com/shibukawa/configdir"
	"github.com/spf13/cobra"
)

const (
	manifestURL = "https://references.taskcluster.net/manifest.json"
)

var (
	pingURLs          PingURLs
	validArgs         []string
	cache             = Cache()
	pingURLsCachePath = filepath.Join("cmds", "status", "pingURLs.json")
)

type (
	PingURLs map[string]string

	CachedURLs struct {
		LastUpdated time.Time `json:"lastUpdated"`
		PingURLs    PingURLs  `json:"pingURLs"`
	}

	PingResponse struct {
		Alive  bool    `json:"alive"`
		Uptime float64 `json:"uptime"`
	}

	API struct {
		BaseURL string     `json:"baseUrl"`
		Entries []APIEntry `json:"entries"`
	}

	APIEntry struct {
		Name  string `json:"name"`
		Route string `json:"route"`
	}
)

// CacheFilePath returns the file system path to the cache file storing the ping URLs
func Cache() (cache *configdir.Config) {
	configDirs := configdir.New("taskcluster", "taskcluster-cli")
	cache = configDirs.QueryCacheFolder()
	return
}

func init() {
	var err error
	pingURLs, err = NewPingURLs()
	if err != nil {
		panic(err)
	}

	validArgs = make([]string, len(pingURLs))
	i := 0
	for k := range pingURLs {
		validArgs[i] = k
		i++
	}
	use := "status"
	for _, validArg := range validArgs {
		use = use + " [" + validArg + "]"
	}
	statusCmd := &cobra.Command{
		Short: "taskcluster-cli status will query the current running status of taskcluster services",
		Long: `When called without arguments, taskcluster-cli status will return the current running
status of all production taskcluster services.

By specifying one or more optional services as arguments, you can limit the
services included in the status report.`,
		PreRunE:            preRun,
		Use:                use,
		ValidArgs:          validArgs,
		RunE:               status,
		DisableFlagParsing: true,
	}

	// Add the task subtree to the root.
	root.Command.AddCommand(statusCmd)
}

// NewPingURLs returns the ping URLs to use. The caller does not need to be
// concerned about whether these URLs are retrieved from a local cache, or from
// querying web services.
func NewPingURLs() (pingURLs PingURLs, err error) {
	if !cache.Exists(pingURLsCachePath) {
		return RefreshCache(manifestURL, cache, pingURLsCachePath)
	}
	cachedURLs, err := ReadCachedURLsFile(cache, pingURLsCachePath)
	if err != nil {
		return
	}
	if cachedURLs.Expired(time.Hour * 24) {
		return RefreshCache(manifestURL, cache, pingURLsCachePath)
	}
	pingURLs = cachedURLs.PingURLs
	return
}

// RefreshCache will scrape the manifest url for a dictionary of taskcluster
// services, and cache the results in file at path.
func RefreshCache(manifestURL string, cache *configdir.Config, cachePath string) (pingURLs PingURLs, err error) {
	pingURLs, err = ScrapePingURLs(manifestURL)
	if err != nil {
		return
	}
	cachedURLs, err := pingURLs.Cache(cache, cachePath)
	return cachedURLs.PingURLs, err
}

// ReadCachedURLsFile returns a *CachedURLs based on the contents of the file
// with the given path.
func ReadCachedURLsFile(cache *configdir.Config, cachePath string) (cachedURLs *CachedURLs, err error) {
	var cachedURLsBytes []byte
	cachedURLsBytes, err = cache.ReadFile(cachePath)
	if err != nil {
		return
	}
	err = json.Unmarshal(cachedURLsBytes, &cachedURLs)
	return
}

// Cache writes the pingURLs p to a file at path (replacing if it exists
// already, and creating parent folders, if required), using the current time
// for the retrieval timestamp.
func (p PingURLs) Cache(cache *configdir.Config, cachePath string) (cachedURLs *CachedURLs, err error) {
	color.Magenta("Writing cache file %v", filepath.Join(cache.Path, cachePath))

	///////////////////////////////////////////////////////////////////////
	// workaround until https://github.com/shibukawa/configdir/pull/3 lands
	parentDir := filepath.Dir(filepath.Join(cache.Path, cachePath))
	err = os.MkdirAll(parentDir, 0755)
	if err != nil {
		return
	}
	///////////////////////////////////////////////////////////////////////

	cachedURLs = &CachedURLs{
		LastUpdated: time.Now(),
		PingURLs:    p,
	}
	var bytes []byte
	bytes, err = json.MarshalIndent(cachedURLs, "", "  ")
	if err != nil {
		return
	}
	err = cache.WriteFile(cachePath, bytes)
	return
}

func (cachedURLs *CachedURLs) Expired(d time.Duration) bool {
	return time.Since(cachedURLs.LastUpdated) > d
}

func preRun(cmd *cobra.Command, args []string) error {
	return validateArgs(cmd, args)
}

//  ScrapePingURLs queries manifestURL to return a manifest of services, which
//  are then queried to fetch ping URLs for taskcluster services
func ScrapePingURLs(manifestURL string) (pingURLs PingURLs, err error) {
	color.Yellow("Scraping ping URLs from %v", manifestURL)
	var allAPIs map[string]string
	err = objectFromJsonURL(manifestURL, &allAPIs)
	if err != nil {
		return
	}
	pingURLs = map[string]string{}
	for _, apiURL := range allAPIs {
		reference := new(API)
		err = objectFromJsonURL(apiURL, reference)
		if err != nil {
			return
		}

		// loop through entries to find a /ping endpoint
		for _, entry := range reference.Entries {
			if entry.Name == "ping" {
				// determine hostname
				var u *url.URL
				u, err = url.Parse(reference.BaseURL)
				if err != nil {
					return
				}
				hostname := u.Hostname()
				service := strings.SplitN(hostname, ".", 2)[0]
				pingURLs[service] = reference.BaseURL + entry.Route
				break
			}
		}
	}
	return
}

func objectFromJsonURL(urlReturningJSON string, object interface{}) (err error) {
	resp, err := http.Get(urlReturningJSON)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if resp.StatusCode != 200 {
		return fmt.Errorf("Bad (!= 200) status code %v from (*URL) Hostnamerl %v", resp.StatusCode, urlReturningJSON)
	}
	decoder := json.NewDecoder(resp.Body)
	err = decoder.Decode(&object)
	if err != nil {
		return err
	}
	return nil
}

func validateArgs(cmd *cobra.Command, args []string) error {
outer:
	for _, arg := range args {
		for _, validArg := range cmd.ValidArgs {
			if arg == validArg {
				continue outer
			}
		}
		return fmt.Errorf("invalid argument(s) passed")
	}
	return nil
}

func respbody(service string) error {
	var servstat PingResponse
	err := objectFromJsonURL(pingURLs[service], &servstat)
	if err != nil {
		return err
	}
	if servstat.Alive == true {
		living := "Alive"
		fmt.Printf("      %v\n", service)
		color.Green("      %v\n", living)
	}

	return nil
}

func status(cmd *cobra.Command, args []string) error {
	if len(args) == 0 {
		args = validArgs
	}
	for _, service := range args {
		err := respbody(service)
		if err != nil {
			panic(err)
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package parser

import (
	"encoding/xml"
	"io"
	"container/list"
	"appengine/datastore"
	"appengine"
	"models"
	"sysutils"
	"timeutils"
	"fmt"
	"strings"
	"time"
)

type Meter struct {
	InternalTime string `xml:"InternalTime,attr"`
	DisplayTime  string `xml:"DisplayTime,attr"`
	Value        int    `xml:"Value,attr"`
}

type Event struct {
	InternalTime string `xml:"InternalTime,attr"`
	DisplayTime  string `xml:"DisplayTime,attr"`
	EventTime    string `xml:"EventTime,attr"`
	EventType    string `xml:"EventType,attr"`
	Description  string `xml:"Decription,attr"`
}

func ParseContent(context appengine.Context, reader io.Reader, batchSize int, parentKey *datastore.Key, readsBatchHandler func (context appengine.Context, userProfileKey *datastore.Key, carbs []models.DayOfReads) ([] *datastore.Key, error), carbsBatchHandler func (context appengine.Context, userProfileKey *datastore.Key, carbs []models.CarbIntake) ([] *datastore.Key, error), injectionBatchHandler func (context appengine.Context, userProfileKey *datastore.Key, injections []models.Injection) ([] *datastore.Key, error), exerciseBatchHandler func (context appengine.Context, userProfileKey *datastore.Key, exercises []models.Exercise) ([] *datastore.Key, error)) (lastReadTime time.Time) {
	decoder := xml.NewDecoder(reader)
	reads := make([]models.MeterRead,0, batchSize)
	daysOfReads := make([]models.DayOfReads,0, 1)
	injections := make([]models.Injection,0, batchSize)
	carbIntakes := make([]models.CarbIntake,0, batchSize)
	exercises := make([]models.Exercise,0, batchSize)

	var lastRead models.MeterRead
	for {
		// Read tokens from the XML document in a stream.
		t, _ := decoder.Token()
		if t == nil {
			context.Debugf("finished reading file")
			break
		}

		// Inspect the type of the token just read.
		switch se := t.(type) {
		case xml.StartElement:
			// If we just read a StartElement token
			// ...and its name is "Glucose"
			switch se.Name.Local {
			case "Glucose":
				var read Meter
				// decode a whole chunk of following XML into the
				decoder.DecodeElement(&read, &se)
				if (read.Value > 0) {
					meterRead := models.MeterRead{read.DisplayTime, models.TimeValue(timeutils.GetTimeInSeconds(read.InternalTime)), read.Value}
					// This should only happen once as we start parsing, we initialize the previous day to the current
					// and the rest of the logic should gracefully handle this case
					if (len(reads) == 0) {
						lastRead = meterRead
					}

					// We're crossing a day boundery, we cut a batch store it and start a new one with the most recently
					// read read. This assumes that we will never get a gap big enough that two consecutive reads could
					// have the same day value while being months apart.
					if meterRead.GetTime().Day() != lastRead.GetTime().Day() {
						// Create a day of reads and append it to the batch
						daysOfReads = append(daysOfReads, models.DayOfReads{reads})

						//if (len(daysOfReads) == batchSize) {
							// Send the batch to be handled and restart another one
						    readsBatchHandler(context, parentKey, daysOfReads)
							daysOfReads = make([]models.DayOfReads,0, 1)
						//}

						reads = make([]models.MeterRead,0, batchSize)
					}

					reads = append(reads, meterRead)
					lastRead = meterRead
				}
			case "Event":
				var event Event
				decoder.DecodeElement(&event, &se)
				if (event.EventType == "Carbs") {
					var carbQuantityInGrams int
					fmt.Sscanf(event.Description, "Carbs %d grams", &carbQuantityInGrams)
					carbIntake := models.CarbIntake{event.EventTime, models.TimeValue(timeutils.GetTimeInSeconds(event.InternalTime)), float32(carbQuantityInGrams), models.UNDEFINED_READ}
					carbIntakes = append(carbIntakes, carbIntake)
					if (len(carbIntakes) == batchSize) {
						// Send the batch to be handled and restart another one
						carbsBatchHandler(context, parentKey, carbIntakes)
						carbIntakes = make([]models.CarbIntake,0, batchSize)
					}
				} else if (event.EventType == "Insulin") {
					var insulinUnits float32
					_, err := fmt.Sscanf(event.Description, "Insulin %f units", &insulinUnits)
					if err != nil {
						sysutils.Propagate(err)
					}
					injection := models.Injection{event.EventTime, models.TimeValue(timeutils.GetTimeInSeconds(event.InternalTime)), float32(insulinUnits), models.UNDEFINED_READ}
					injections = append(injections, injection)
					if (len(injections) == batchSize) {
						// Send the batch to be handled and restart another one
						injectionBatchHandler(context, parentKey, injections)
						injections = make([]models.Injection,0, batchSize)
					}
				} else if (strings.HasPrefix(event.EventType, "Exercise")) {
					var duration int
					var intensity string
					fmt.Sscanf(event.Description, "Exercise %s (%d minutes)", &intensity, &duration)
					exercise := models.Exercise{event.EventTime, models.TimeValue(timeutils.GetTimeInSeconds(event.InternalTime)), duration, intensity}
					exercises = append(exercises, exercise)
					if (len(exercises) == batchSize) {
						// Send the batch to be handled and restart another one
						exerciseBatchHandler(context, parentKey, exercises)
						exercises = make([]models.Exercise,0, batchSize)
					}
				}

			case "Meter":
				// TODO: Read the meter calibrations?
			}
		}
	}

	// Run the final batch for each
	if (len(reads) > 0) {
		daysOfReads = append(daysOfReads, models.DayOfReads{reads})
		context.Infof("Flushing %d days of reads", len(daysOfReads))
		readsBatchHandler(context, parentKey, daysOfReads)
	}

	if (len(injections) > 0) {
		// Send the batch to be handled and restart another one
		injectionBatchHandler(context, parentKey, injections)
	}

	if (len(carbIntakes) > 0) {
		// Send the batch to be handled and restart another one
		carbsBatchHandler(context, parentKey, carbIntakes)
	}

	if (len(exercises) > 0) {
		// Send the batch to be handled and restart another one
		exerciseBatchHandler(context, parentKey, exercises)
	}

	context.Infof("Done parsing and storing all data")
	return lastRead.GetTime()
}

func ConvertAsReadsArray(meterReads *list.List) (reads []models.MeterRead) {
	reads = make([]models.MeterRead, meterReads.Len())
	for e, i := meterReads.Front(), 0; e != nil; e, i = e.Next(), i + 1 {
		meter := e.Value.(Meter)
		reads[i] = models.MeterRead{meter.DisplayTime, models.TimeValue(timeutils.GetTimeInSeconds(meter.InternalTime)), meter.Value}
	}

	return reads
}
<commit_msg>Add back to batching for the days of reads.<commit_after>package parser

import (
	"encoding/xml"
	"io"
	"container/list"
	"appengine/datastore"
	"appengine"
	"models"
	"sysutils"
	"timeutils"
	"fmt"
	"strings"
	"time"
)

type Meter struct {
	InternalTime string `xml:"InternalTime,attr"`
	DisplayTime  string `xml:"DisplayTime,attr"`
	Value        int    `xml:"Value,attr"`
}

type Event struct {
	InternalTime string `xml:"InternalTime,attr"`
	DisplayTime  string `xml:"DisplayTime,attr"`
	EventTime    string `xml:"EventTime,attr"`
	EventType    string `xml:"EventType,attr"`
	Description  string `xml:"Decription,attr"`
}

func ParseContent(context appengine.Context, reader io.Reader, batchSize int, parentKey *datastore.Key, readsBatchHandler func (context appengine.Context, userProfileKey *datastore.Key, carbs []models.DayOfReads) ([] *datastore.Key, error), carbsBatchHandler func (context appengine.Context, userProfileKey *datastore.Key, carbs []models.CarbIntake) ([] *datastore.Key, error), injectionBatchHandler func (context appengine.Context, userProfileKey *datastore.Key, injections []models.Injection) ([] *datastore.Key, error), exerciseBatchHandler func (context appengine.Context, userProfileKey *datastore.Key, exercises []models.Exercise) ([] *datastore.Key, error)) (lastReadTime time.Time) {
	decoder := xml.NewDecoder(reader)
	reads := make([]models.MeterRead,0, batchSize)
	daysOfReads := make([]models.DayOfReads,0, batchSize)
	injections := make([]models.Injection,0, batchSize)
	carbIntakes := make([]models.CarbIntake,0, batchSize)
	exercises := make([]models.Exercise,0, batchSize)

	var lastRead models.MeterRead
	for {
		// Read tokens from the XML document in a stream.
		t, _ := decoder.Token()
		if t == nil {
			context.Debugf("finished reading file")
			break
		}

		// Inspect the type of the token just read.
		switch se := t.(type) {
		case xml.StartElement:
			// If we just read a StartElement token
			// ...and its name is "Glucose"
			switch se.Name.Local {
			case "Glucose":
				var read Meter
				// decode a whole chunk of following XML into the
				decoder.DecodeElement(&read, &se)
				if (read.Value > 0) {
					meterRead := models.MeterRead{read.DisplayTime, models.TimeValue(timeutils.GetTimeInSeconds(read.InternalTime)), read.Value}
					// This should only happen once as we start parsing, we initialize the previous day to the current
					// and the rest of the logic should gracefully handle this case
					if (len(reads) == 0) {
						lastRead = meterRead
					}

					// We're crossing a day boundery, we cut a batch store it and start a new one with the most recently
					// read read. This assumes that we will never get a gap big enough that two consecutive reads could
					// have the same day value while being months apart.
					if meterRead.GetTime().Day() != lastRead.GetTime().Day() {
						// Create a day of reads and append it to the batch
						daysOfReads = append(daysOfReads, models.DayOfReads{reads})

						if (len(daysOfReads) == batchSize) {
							// Send the batch to be handled and restart another one
						    readsBatchHandler(context, parentKey, daysOfReads)
							daysOfReads = make([]models.DayOfReads,0, batchSize)
						}

						reads = make([]models.MeterRead,0, batchSize)
					}

					reads = append(reads, meterRead)
					lastRead = meterRead
				}
			case "Event":
				var event Event
				decoder.DecodeElement(&event, &se)
				if (event.EventType == "Carbs") {
					var carbQuantityInGrams int
					fmt.Sscanf(event.Description, "Carbs %d grams", &carbQuantityInGrams)
					carbIntake := models.CarbIntake{event.EventTime, models.TimeValue(timeutils.GetTimeInSeconds(event.InternalTime)), float32(carbQuantityInGrams), models.UNDEFINED_READ}
					carbIntakes = append(carbIntakes, carbIntake)
					if (len(carbIntakes) == batchSize) {
						// Send the batch to be handled and restart another one
						carbsBatchHandler(context, parentKey, carbIntakes)
						carbIntakes = make([]models.CarbIntake,0, batchSize)
					}
				} else if (event.EventType == "Insulin") {
					var insulinUnits float32
					_, err := fmt.Sscanf(event.Description, "Insulin %f units", &insulinUnits)
					if err != nil {
						sysutils.Propagate(err)
					}
					injection := models.Injection{event.EventTime, models.TimeValue(timeutils.GetTimeInSeconds(event.InternalTime)), float32(insulinUnits), models.UNDEFINED_READ}
					injections = append(injections, injection)
					if (len(injections) == batchSize) {
						// Send the batch to be handled and restart another one
						injectionBatchHandler(context, parentKey, injections)
						injections = make([]models.Injection,0, batchSize)
					}
				} else if (strings.HasPrefix(event.EventType, "Exercise")) {
					var duration int
					var intensity string
					fmt.Sscanf(event.Description, "Exercise %s (%d minutes)", &intensity, &duration)
					exercise := models.Exercise{event.EventTime, models.TimeValue(timeutils.GetTimeInSeconds(event.InternalTime)), duration, intensity}
					exercises = append(exercises, exercise)
					if (len(exercises) == batchSize) {
						// Send the batch to be handled and restart another one
						exerciseBatchHandler(context, parentKey, exercises)
						exercises = make([]models.Exercise,0, batchSize)
					}
				}

			case "Meter":
				// TODO: Read the meter calibrations?
			}
		}
	}

	// Run the final batch for each
	if (len(reads) > 0) {
		daysOfReads = append(daysOfReads, models.DayOfReads{reads})
		context.Infof("Flushing %d days of reads", len(daysOfReads))
		readsBatchHandler(context, parentKey, daysOfReads)
	}

	if (len(injections) > 0) {
		// Send the batch to be handled and restart another one
		injectionBatchHandler(context, parentKey, injections)
	}

	if (len(carbIntakes) > 0) {
		// Send the batch to be handled and restart another one
		carbsBatchHandler(context, parentKey, carbIntakes)
	}

	if (len(exercises) > 0) {
		// Send the batch to be handled and restart another one
		exerciseBatchHandler(context, parentKey, exercises)
	}

	context.Infof("Done parsing and storing all data")
	return lastRead.GetTime()
}

func ConvertAsReadsArray(meterReads *list.List) (reads []models.MeterRead) {
	reads = make([]models.MeterRead, meterReads.Len())
	for e, i := meterReads.Front(), 0; e != nil; e, i = e.Next(), i + 1 {
		meter := e.Value.(Meter)
		reads[i] = models.MeterRead{meter.DisplayTime, models.TimeValue(timeutils.GetTimeInSeconds(meter.InternalTime)), meter.Value}
	}

	return reads
}
<|endoftext|>


<commit_before>package parser

import (
	"bytes"
	"fmt"
)

// Parser defines the interface implemented by all combinable parsers.
type Parser interface {
	Parse(sc Scanner) ParseResult
}

func fail(at TextPos, format string, a ...interface{}) ParseResult {
	return &FailedResult{
		err:       fmt.Errorf(format, a...),
		textRange: TextRange{at, at},
	}
}

// EOFParser expects just EOF.
type EOFParser struct{}

// EOF returns a parser that expects just EOF.
func EOF() Parser {
	return &EOFParser{}
}

// Parse parses the input.
func (p *EOFParser) Parse(sc Scanner) ParseResult {
	r, err := sc.Read()
	if err == nil {
		return fail(sc.GetPos(), "expected EOF, got %c", r)
	}
	return &SuccessResult{
		textRange: TextRange{sc.GetPos(), sc.GetPos()},
		result:    "",
	}
}

// CharRangeParser parses any single character in a range, inclusive.
type CharRangeParser struct {
	min rune // both inclusive
	max rune
}

// Char returns a parser that parses a single occurance of that rune.
func Char(c rune) Parser {
	return &CharRangeParser{c, c}
}

// CharRange returns a parser that parses a single occurance of any
// rune in the given range, inclusive.
func CharRange(min, max rune) Parser {
	return &CharRangeParser{min, max}
}

// Parse parses the input.
func (p *CharRangeParser) Parse(sc Scanner) ParseResult {
	start := sc.GetPos()
	r, err := sc.Read()
	if err != nil {
		return fail(sc.GetPos(), "expected a character, got error %v", err)
	}
	if r < p.min || r > p.max {
		return fail(sc.GetPos(), "expected a character in the range, got error %c", r)
	}
	return &SuccessResult{
		textRange: TextRange{start, sc.GetPos()},
		result:    r,
	}
}

// TokenParser works like a series of CharRangeParsers, but is more
// efficient.
type TokenParser struct {
	token string
}

// Token returns a parser that parses the exact string given.
func Token(token string) Parser {
	return &TokenParser{token}
}

// Parse parses the input.
func (p *TokenParser) Parse(sc Scanner) ParseResult {
	start := sc.GetPos()
	seen := []rune{}
	for _, c := range p.token {
		r, err := sc.Read()
		seen = append(seen, r)
		if err != nil {
			return fail(sc.GetPos(), "expected '%s', got error %v", p.token, err)
		}
		if r != c {
			return fail(sc.GetPos(), "expected '%s', got '%s'", p.token, string(seen))
		}
	}
	return &SuccessResult{
		textRange: TextRange{start, sc.GetPos()},
		result:    string(seen),
	}
}

// CharSetParser parses any single character in the set.
type CharSetParser struct {
	allowed map[rune]struct{}
}

// AnyCharIn returns a parser that parses a single occurance of any
// rune in the given string.
func AnyCharIn(s string) Parser {
	allowed := make(map[rune]struct{}, len(s))
	for _, r := range s {
		allowed[r] = struct{}{}
	}
	return &CharSetParser{allowed}
}

// AnyChar returns a parser that parses a single occurance of any rune
// given.
func AnyChar(rs ...rune) Parser {
	allowed := make(map[rune]struct{}, len(rs))
	for _, r := range rs {
		allowed[r] = struct{}{}
	}
	return &CharSetParser{allowed}
}

// Parse parses the input.
func (p *CharSetParser) Parse(sc Scanner) ParseResult {
	start := sc.GetPos()
	r, err := sc.Read()
	if err != nil {
		return fail(sc.GetPos(), "expected a character, got error %v", err)
	}
	if _, ok := p.allowed[r]; !ok {
		return fail(sc.GetPos(), "expected a character in the set, got error %c", r)
	}
	return &SuccessResult{
		textRange: TextRange{start, sc.GetPos()},
		result:    r,
	}
}

// SeqParser combines multiple parsers in sequence.
type SeqParser struct {
	parsers []Parser
}

// Sequence returns a parser that runs each given parser in series and
// combines the result.
func Sequence(parsers ...Parser) Parser {
	return &SeqParser{parsers}
}

// Parse parses the input.
func (p *SeqParser) Parse(sc Scanner) ParseResult {
	var textRange TextRange
	textRange.start = sc.GetPos()
	results := []interface{}{}

	for _, inner := range p.parsers {
		innerResult := inner.Parse(sc)
		// Return errors right away
		if !innerResult.Matched() {
			return innerResult
		}

		textRange.end = innerResult.TextRange().end
		results = append(results, innerResult.Result())
	}

	return &SuccessResult{
		textRange: textRange,
		result:    cleanupResult(results),
	}
}

func cleanupResult(results []interface{}) interface{} {
	var buffer bytes.Buffer
	allStr := true
	for _, result := range results {
		if result == "" {
			continue
		}
		if r, ok := result.(rune); ok {
			buffer.WriteRune(r)
		} else if s, ok := result.(string); ok {
			buffer.WriteString(s)
		} else {
			allStr = false
			break
		}
	}
	if allStr {
		return buffer.String()
	}
	return results
}

// Wrapper modifies the result of a parser with a function.
type Wrapper struct {
	inner Parser
	fn    func(interface{}) interface{}
}

// ParseWith returns a parser that will apply the given function to
// the result of parsing, if the parser was successful.
func ParseWith(p Parser, fn func(interface{}) interface{}) Parser {
	return &Wrapper{inner: p, fn: fn}
}

// Parse parses the input.
func (p *Wrapper) Parse(sc Scanner) ParseResult {
	innerResult := p.inner.Parse(sc)
	if innerResult.Matched() {
		return &SuccessResult{
			textRange: innerResult.TextRange(),
			result:    p.fn(innerResult.Result()),
		}
	}
	return innerResult
}

// MaybeParser tries to run the inner parser, but allows the inner
// parser to fail.
type MaybeParser struct {
	inner Parser
}

// Maybe returns a parser that parses 0 or 1 occurances of the given
// parser.
func Maybe(inner Parser) Parser {
	return &MaybeParser{inner}
}

// Parse parses the input.
func (p *MaybeParser) Parse(sc Scanner) ParseResult {
	sc.StartSnapshot()

	innerResult := p.inner.Parse(sc)
	if innerResult.Matched() {
		sc.PopSnapshot()
		return innerResult
	}

	sc.RewindSnapshot()
	start := sc.GetPos()
	return &SuccessResult{
		textRange: TextRange{start, start},
		result:    "",
	}
}

// ManyParser Matches 0+ occurrences
type ManyParser struct {
	inner Parser
}

// Many returns a parser that matches the given parser zero or more
// times, and combines the results.
func Many(inner Parser) Parser {
	return &ManyParser{inner}
}

// Parse parses the input.
func (p *ManyParser) Parse(sc Scanner) ParseResult {
	var textRange TextRange
	textRange.start = sc.GetPos()
	results := []interface{}{}

	for true {
		sc.StartSnapshot()
		innerResult := p.inner.Parse(sc)

		if innerResult.Matched() {
			sc.PopSnapshot()
			results = append(results, innerResult.Result())
		} else {
			sc.RewindSnapshot()
			break
		}
	}

	textRange.end = sc.GetPos()
	return &SuccessResult{
		textRange: textRange,
		result:    cleanupResult(results),
	}
}

// OrParser parses at most one of the inner parses.
type OrParser struct {
	parsers []Parser
}

// Or returns a parser that accepts the union of the languages
// accepted by the given parsers.
func Or(parsers ...Parser) Parser {
	return &OrParser{parsers}
}

// Parse parses the input.
func (p *OrParser) Parse(sc Scanner) ParseResult {
	for _, inner := range p.parsers {
		sc.StartSnapshot()
		innerResult := inner.Parse(sc)

		if innerResult.Matched() {
			sc.PopSnapshot()
			return innerResult
		}
		sc.RewindSnapshot()
	}

	return fail(sc.GetPos(), "no parser matched")
}
<commit_msg>Fix misspelling<commit_after>package parser

import (
	"bytes"
	"fmt"
)

// Parser defines the interface implemented by all combinable parsers.
type Parser interface {
	Parse(sc Scanner) ParseResult
}

func fail(at TextPos, format string, a ...interface{}) ParseResult {
	return &FailedResult{
		err:       fmt.Errorf(format, a...),
		textRange: TextRange{at, at},
	}
}

// EOFParser expects just EOF.
type EOFParser struct{}

// EOF returns a parser that expects just EOF.
func EOF() Parser {
	return &EOFParser{}
}

// Parse parses the input.
func (p *EOFParser) Parse(sc Scanner) ParseResult {
	r, err := sc.Read()
	if err == nil {
		return fail(sc.GetPos(), "expected EOF, got %c", r)
	}
	return &SuccessResult{
		textRange: TextRange{sc.GetPos(), sc.GetPos()},
		result:    "",
	}
}

// CharRangeParser parses any single character in a range, inclusive.
type CharRangeParser struct {
	min rune // both inclusive
	max rune
}

// Char returns a parser that parses a single occurrence of that rune.
func Char(c rune) Parser {
	return &CharRangeParser{c, c}
}

// CharRange returns a parser that parses a single occurrence of any
// rune in the given range, inclusive.
func CharRange(min, max rune) Parser {
	return &CharRangeParser{min, max}
}

// Parse parses the input.
func (p *CharRangeParser) Parse(sc Scanner) ParseResult {
	start := sc.GetPos()
	r, err := sc.Read()
	if err != nil {
		return fail(sc.GetPos(), "expected a character, got error %v", err)
	}
	if r < p.min || r > p.max {
		return fail(sc.GetPos(), "expected a character in the range, got error %c", r)
	}
	return &SuccessResult{
		textRange: TextRange{start, sc.GetPos()},
		result:    r,
	}
}

// TokenParser works like a series of CharRangeParsers, but is more
// efficient.
type TokenParser struct {
	token string
}

// Token returns a parser that parses the exact string given.
func Token(token string) Parser {
	return &TokenParser{token}
}

// Parse parses the input.
func (p *TokenParser) Parse(sc Scanner) ParseResult {
	start := sc.GetPos()
	seen := []rune{}
	for _, c := range p.token {
		r, err := sc.Read()
		seen = append(seen, r)
		if err != nil {
			return fail(sc.GetPos(), "expected '%s', got error %v", p.token, err)
		}
		if r != c {
			return fail(sc.GetPos(), "expected '%s', got '%s'", p.token, string(seen))
		}
	}
	return &SuccessResult{
		textRange: TextRange{start, sc.GetPos()},
		result:    string(seen),
	}
}

// CharSetParser parses any single character in the set.
type CharSetParser struct {
	allowed map[rune]struct{}
}

// AnyCharIn returns a parser that parses a single occurrence of any
// rune in the given string.
func AnyCharIn(s string) Parser {
	allowed := make(map[rune]struct{}, len(s))
	for _, r := range s {
		allowed[r] = struct{}{}
	}
	return &CharSetParser{allowed}
}

// AnyChar returns a parser that parses a single occurrence of any rune
// given.
func AnyChar(rs ...rune) Parser {
	allowed := make(map[rune]struct{}, len(rs))
	for _, r := range rs {
		allowed[r] = struct{}{}
	}
	return &CharSetParser{allowed}
}

// Parse parses the input.
func (p *CharSetParser) Parse(sc Scanner) ParseResult {
	start := sc.GetPos()
	r, err := sc.Read()
	if err != nil {
		return fail(sc.GetPos(), "expected a character, got error %v", err)
	}
	if _, ok := p.allowed[r]; !ok {
		return fail(sc.GetPos(), "expected a character in the set, got error %c", r)
	}
	return &SuccessResult{
		textRange: TextRange{start, sc.GetPos()},
		result:    r,
	}
}

// SeqParser combines multiple parsers in sequence.
type SeqParser struct {
	parsers []Parser
}

// Sequence returns a parser that runs each given parser in series and
// combines the result.
func Sequence(parsers ...Parser) Parser {
	return &SeqParser{parsers}
}

// Parse parses the input.
func (p *SeqParser) Parse(sc Scanner) ParseResult {
	var textRange TextRange
	textRange.start = sc.GetPos()
	results := []interface{}{}

	for _, inner := range p.parsers {
		innerResult := inner.Parse(sc)
		// Return errors right away
		if !innerResult.Matched() {
			return innerResult
		}

		textRange.end = innerResult.TextRange().end
		results = append(results, innerResult.Result())
	}

	return &SuccessResult{
		textRange: textRange,
		result:    cleanupResult(results),
	}
}

func cleanupResult(results []interface{}) interface{} {
	var buffer bytes.Buffer
	allStr := true
	for _, result := range results {
		if result == "" {
			continue
		}
		if r, ok := result.(rune); ok {
			buffer.WriteRune(r)
		} else if s, ok := result.(string); ok {
			buffer.WriteString(s)
		} else {
			allStr = false
			break
		}
	}
	if allStr {
		return buffer.String()
	}
	return results
}

// Wrapper modifies the result of a parser with a function.
type Wrapper struct {
	inner Parser
	fn    func(interface{}) interface{}
}

// ParseWith returns a parser that will apply the given function to
// the result of parsing, if the parser was successful.
func ParseWith(p Parser, fn func(interface{}) interface{}) Parser {
	return &Wrapper{inner: p, fn: fn}
}

// Parse parses the input.
func (p *Wrapper) Parse(sc Scanner) ParseResult {
	innerResult := p.inner.Parse(sc)
	if innerResult.Matched() {
		return &SuccessResult{
			textRange: innerResult.TextRange(),
			result:    p.fn(innerResult.Result()),
		}
	}
	return innerResult
}

// MaybeParser tries to run the inner parser, but allows the inner
// parser to fail.
type MaybeParser struct {
	inner Parser
}

// Maybe returns a parser that parses 0 or 1 occurrences of the given
// parser.
func Maybe(inner Parser) Parser {
	return &MaybeParser{inner}
}

// Parse parses the input.
func (p *MaybeParser) Parse(sc Scanner) ParseResult {
	sc.StartSnapshot()

	innerResult := p.inner.Parse(sc)
	if innerResult.Matched() {
		sc.PopSnapshot()
		return innerResult
	}

	sc.RewindSnapshot()
	start := sc.GetPos()
	return &SuccessResult{
		textRange: TextRange{start, start},
		result:    "",
	}
}

// ManyParser Matches 0+ occurrences
type ManyParser struct {
	inner Parser
}

// Many returns a parser that matches the given parser zero or more
// times, and combines the results.
func Many(inner Parser) Parser {
	return &ManyParser{inner}
}

// Parse parses the input.
func (p *ManyParser) Parse(sc Scanner) ParseResult {
	var textRange TextRange
	textRange.start = sc.GetPos()
	results := []interface{}{}

	for true {
		sc.StartSnapshot()
		innerResult := p.inner.Parse(sc)

		if innerResult.Matched() {
			sc.PopSnapshot()
			results = append(results, innerResult.Result())
		} else {
			sc.RewindSnapshot()
			break
		}
	}

	textRange.end = sc.GetPos()
	return &SuccessResult{
		textRange: textRange,
		result:    cleanupResult(results),
	}
}

// OrParser parses at most one of the inner parses.
type OrParser struct {
	parsers []Parser
}

// Or returns a parser that accepts the union of the languages
// accepted by the given parsers.
func Or(parsers ...Parser) Parser {
	return &OrParser{parsers}
}

// Parse parses the input.
func (p *OrParser) Parse(sc Scanner) ParseResult {
	for _, inner := range p.parsers {
		sc.StartSnapshot()
		innerResult := inner.Parse(sc)

		if innerResult.Matched() {
			sc.PopSnapshot()
			return innerResult
		}
		sc.RewindSnapshot()
	}

	return fail(sc.GetPos(), "no parser matched")
}
<|endoftext|>


<commit_before>package parser

import (
	"io/ioutil"
	"path/filepath"
	"encoding/json"
	"errors"
)

type Golt struct {
	Golt []GoltJson `json:"golt"`
}

type GoltJson struct {
	URL string `json:"url"`
	Method string `json:"method"`
	Payload string `json:"body"`
	Threads int `json:"threads"`
	Repetitions int `json:"repetitions"`
	Duration int `json:"duration"`
	Stage int `json:"stage"`
	Assert struct {
			Timeout int `json:"timeout"`
			Status int `json:"status"`
			Headers struct {
					} `json:"headers"`
			Body string `json:"body"`
		} `json:"assert"`
}

func ParseInputFile(filename string) (Golt, error) {
	file, err := ioutil.ReadFile(filename)
	if err != nil {
		return Golt{}, err
	}

	switch filepath.Ext(filename) {
		case ".json":
			golt, err := jsonToStruct(file)
			return golt, err
		case ".yaml":
			return Golt{}, errors.New("We're dealing with YAML, but it's not yet implemented. Sorry !")
		default:
			return Golt{}, errors.New("Unknown file type, exiting")
	}
}

func jsonToStruct(file []byte) (Golt, error) {
	var golt Golt
	err := json.Unmarshal(file, &golt)
	return golt, err
}<commit_msg>Removed inner structure of Golt struct and made it external<commit_after>package parser

import (
	"io/ioutil"
	"path/filepath"
	"encoding/json"
	"errors"
)

type Golt struct {
	Golt []GoltJson `json:"golt"`
}

type GoltJson struct {
	URL string `json:"url"`
	Method string `json:"method"`
	Payload string `json:"body"`
	Threads int `json:"threads"`
	Repetitions int `json:"repetitions"`
	Duration int `json:"duration"`
	Stage int `json:"stage"`
	Assert GoltAssert`json:"assert"`
}

type GoltAssert struct {
	Timeout int `json:"timeout"`
	Status int `json:"status"`
	Headers struct {} `json:"headers"`
	Body string `json:"body"`
}

func ParseInputFile(filename string) (Golt, error) {
	file, err := ioutil.ReadFile(filename)
	if err != nil {
		return Golt{}, err
	}

	switch filepath.Ext(filename) {
		case ".json":
			golt, err := jsonToStruct(file)
			return golt, err
		case ".yaml":
			return Golt{}, errors.New("We're dealing with YAML, but it's not yet implemented. Sorry !")
		default:
			return Golt{}, errors.New("Unknown file type, exiting")
	}
}

func jsonToStruct(file []byte) (Golt, error) {
	var golt Golt
	err := json.Unmarshal(file, &golt)
	return golt, err
}<|endoftext|>